diff --git a/.changeset/tasty-animals-grab.md b/.changeset/tasty-animals-grab.md new file mode 100644 index 00000000000..a5ba5caec27 --- /dev/null +++ b/.changeset/tasty-animals-grab.md @@ -0,0 +1,5 @@ +--- +'@clerk/ui': patch +--- + +Fix "You must belong to an organization" screen showing when user has existing memberships, invitations or suggestions diff --git a/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx b/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx index 28952bd96c9..5cf4ed8e53f 100644 --- a/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx +++ b/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/__tests__/TaskChooseOrganization.test.tsx @@ -3,7 +3,10 @@ import { describe, expect, it } from 'vitest'; import { bindCreateFixtures } from '@/test/create-fixtures'; import { render } from '@/test/utils'; -import { createFakeUserOrganizationMembership } from '@/ui/components/OrganizationSwitcher/__tests__/test-utils'; +import { + createFakeUserOrganizationMembership, + createFakeUserOrganizationSuggestion, +} from '@/ui/components/OrganizationSwitcher/__tests__/test-utils'; import { TaskChooseOrganization } from '..'; @@ -296,5 +299,56 @@ describe('TaskChooseOrganization', () => { expect(queryByText(/you must belong to an organization/i)).toBeInTheDocument(); expect(queryByText(/contact your organization admin for an invitation/i)).toBeInTheDocument(); }); + + it('with existing memberships or suggestions, displays create organization screen', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withForceOrganizationSelection(); + f.withUser({ + create_organization_enabled: false, + }); + }); + + fixtures.clerk.user?.getOrganizationMemberships.mockReturnValueOnce( + Promise.resolve({ + data: [ + createFakeUserOrganizationMembership({ + id: '1', + organization: { + id: '1', + name: 'Existing Org', + slug: 'org1', + membersCount: 1, + adminDeleteEnabled: false, + maxAllowedMemberships: 1, + pendingInvitationsCount: 1, + }, + }), + ], + total_count: 1, + }), + ); + + fixtures.clerk.user?.getOrganizationSuggestions.mockReturnValueOnce( + Promise.resolve({ + data: [ + createFakeUserOrganizationSuggestion({ + id: '2', + emailAddress: 'two@clerk.com', + publicOrganizationData: { + name: 'OrgTwoSuggestion', + }, + }), + ], + total_count: 1, + }), + ); + + const { findByText, queryByRole } = render(, { wrapper }); + + expect(await findByText('Existing Org')).toBeInTheDocument(); + expect(await findByText('Create new organization')).toBeInTheDocument(); + expect(queryByRole('textbox', { name: /name/i })).not.toBeInTheDocument(); + }); }); }); diff --git a/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/index.tsx b/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/index.tsx index 3275a184707..dc3375e0d0b 100644 --- a/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/index.tsx +++ b/packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/index.tsx @@ -1,5 +1,5 @@ import { useClerk, useSession, useUser } from '@clerk/shared/react'; -import { useState, type ComponentType } from 'react'; +import { useState } from 'react'; import { useSignOutContext, withCoreSessionSwitchGuard } from '@/ui/contexts'; import { descriptors, Flex, Flow, localizationKeys, Spinner } from '@/ui/customizables'; @@ -14,24 +14,16 @@ import { ChooseOrganizationScreen } from './ChooseOrganizationScreen'; import { CreateOrganizationScreen } from './CreateOrganizationScreen'; const TaskChooseOrganizationInternal = () => { - const { signOut } = useClerk(); const { user } = useUser(); - const { session } = useSession(); const { userMemberships, userSuggestions, userInvitations } = useOrganizationListInView(); - const { otherSessions } = useMultipleSessions({ user }); - const { navigateAfterSignOut, navigateAfterMultiSessionSingleSignOutUrl } = useSignOutContext(); - - const handleSignOut = () => { - if (otherSessions.length === 0) { - return signOut(navigateAfterSignOut); - } - - return signOut(navigateAfterMultiSessionSingleSignOutUrl, { sessionId: session?.id }); - }; const isLoading = userMemberships?.isLoading || userInvitations?.isLoading || userSuggestions?.isLoading; const hasExistingResources = !!(userMemberships?.count || userInvitations?.count || userSuggestions?.count); - const identifier = user?.primaryEmailAddress?.emailAddress ?? user?.username; + const isOrganizationCreationDisabled = !isLoading && !user?.createOrganizationEnabled && !hasExistingResources; + + if (isOrganizationCreationDisabled) { + return ; + } return ( @@ -127,18 +119,6 @@ const TaskChooseOrganizationFlows = withCardStateProvider((props: TaskChooseOrga return setCurrentFlow('create')} />; }); -export const withOrganizationCreationEnabledGuard = (Component: ComponentType) => { - return (props: T) => { - const { user } = useUser(); - - if (!user?.createOrganizationEnabled) { - return ; - } - - return ; - }; -}; - function OrganizationCreationDisabledScreen() { return ( @@ -163,8 +143,5 @@ function OrganizationCreationDisabledScreen() { } export const TaskChooseOrganization = withCoreSessionSwitchGuard( - withTaskGuard( - withCardStateProvider(withOrganizationCreationEnabledGuard(TaskChooseOrganizationInternal)), - 'choose-organization', - ), + withTaskGuard(withCardStateProvider(TaskChooseOrganizationInternal), 'choose-organization'), );