Skip to content

Commit 87f1fc5

Browse files
authored
fix(ui): Keep role select enabled with default org role (#7567)
1 parent 8fba373 commit 87f1fc5

File tree

3 files changed

+74
-11
lines changed

3 files changed

+74
-11
lines changed

.changeset/social-items-strive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/ui': patch
3+
---
4+
5+
Fix role select being disabled on `OrganizationProfile` invite members page when default role is not in roles list

packages/ui/src/components/OrganizationProfile/InviteMembersForm.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,10 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => {
4848
label: localizationKeys('formFieldLabel__emailAddresses'),
4949
});
5050

51-
const defaultRole = useDefaultRole();
5251
const roleField = useFormControl('role', '', {
5352
label: localizationKeys('formFieldLabel__role'),
5453
});
5554

56-
useEffect(() => {
57-
if (roleField.value || !defaultRole) {
58-
return;
59-
}
60-
61-
roleField.setValue(defaultRole);
62-
}, [defaultRole, roleField]);
63-
6455
if (!organization) {
6556
return null;
6657
}
@@ -200,8 +191,23 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => {
200191

201192
const AsyncRoleSelect = (field: ReturnType<typeof useFormControl<'role'>>) => {
202193
const { options, isLoading, hasRoleSetMigration } = useFetchRoles();
203-
204194
const { t } = useLocalizations();
195+
const defaultRole = useDefaultRole();
196+
197+
useEffect(() => {
198+
if (field.value || !defaultRole) {
199+
return;
200+
}
201+
202+
// Skip if the default role from org settings is not in the current role set
203+
// This will eventually be returned by the roles endpoint, and `organizationSettings.domains.defaultRole` will be deprecated
204+
const defaultRoleExists = options?.some(option => option.value === defaultRole);
205+
if (!defaultRoleExists) {
206+
return;
207+
}
208+
209+
field.setValue(defaultRole);
210+
}, [defaultRole, options, field]);
205211

206212
return (
207213
<Form.ControlRow elementId={field.id}>

packages/ui/src/components/OrganizationProfile/__tests__/InviteMembersPage.test.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ClerkAPIResponseError } from '@clerk/shared/error';
22
import type { OrganizationInvitationResource } from '@clerk/shared/types';
33
import { waitFor } from '@testing-library/react';
4-
import React from 'react';
54
import { beforeEach, describe, expect, it, vi } from 'vitest';
65

76
import { bindCreateFixtures } from '@/test/create-fixtures';
@@ -246,6 +245,59 @@ describe('InviteMembersPage', () => {
246245
await waitFor(() => expect(getByRole('button', { name: /select role/i })).toBeInTheDocument());
247246
});
248247

248+
it('enables selecting other options if default role is not available', async () => {
249+
const { wrapper, fixtures } = await createFixtures(f => {
250+
f.withOrganizations();
251+
f.withOrganizationDomains(undefined, 'mydefaultrole');
252+
f.withUser({
253+
email_addresses: ['[email protected]'],
254+
organization_memberships: [{ name: 'Org1', role: 'admin' }],
255+
});
256+
});
257+
258+
fixtures.clerk.organization?.getInvitations.mockRejectedValue(null);
259+
fixtures.clerk.organization?.getRoles.mockResolvedValue({
260+
total_count: 1,
261+
data: [
262+
{
263+
pathRoot: '',
264+
reload: vi.fn(),
265+
id: 'member',
266+
key: 'member',
267+
name: 'member',
268+
description: '',
269+
permissions: [],
270+
createdAt: new Date(),
271+
updatedAt: new Date(),
272+
},
273+
{
274+
pathRoot: '',
275+
reload: vi.fn(),
276+
id: 'admin',
277+
key: 'admin',
278+
name: 'admin',
279+
description: '',
280+
permissions: [],
281+
createdAt: new Date(),
282+
updatedAt: new Date(),
283+
},
284+
],
285+
});
286+
287+
fixtures.clerk.organization?.inviteMembers.mockResolvedValueOnce([{}] as OrganizationInvitationResource[]);
288+
const { getByRole, userEvent, getByTestId } = render(
289+
<Action.Root>
290+
<InviteMembersScreen />
291+
</Action.Root>,
292+
{ wrapper },
293+
);
294+
await userEvent.type(getByTestId('tag-input'), '[email protected],');
295+
await waitFor(() => expect(getByRole('button', { name: /select role/i })).toBeInTheDocument());
296+
await userEvent.click(getByRole('button', { name: /select role/i }));
297+
await userEvent.click(getByRole('button', { name: /admin/i }));
298+
await waitFor(() => expect(getByRole('button', { name: 'Send invitations' })).not.toBeDisabled());
299+
});
300+
249301
it('enables send button with default role once email address has been entered', async () => {
250302
const defaultRole = 'mydefaultrole';
251303

0 commit comments

Comments
 (0)