Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dry-rings-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Fix role select being disabled on `OrganizationProfile` invite members page when default role is not in roles list
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,10 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => {
label: localizationKeys('formFieldLabel__emailAddresses'),
});

const defaultRole = useDefaultRole();
const roleField = useFormControl('role', '', {
label: localizationKeys('formFieldLabel__role'),
});

useEffect(() => {
if (roleField.value || !defaultRole) {
return;
}

roleField.setValue(defaultRole);
}, [defaultRole, roleField]);

if (!organization) {
return null;
}
Expand Down Expand Up @@ -200,8 +191,23 @@ export const InviteMembersForm = (props: InviteMembersFormProps) => {

const AsyncRoleSelect = (field: ReturnType<typeof useFormControl<'role'>>) => {
const { options, isLoading, hasRoleSetMigration } = useFetchRoles();

const { t } = useLocalizations();
const defaultRole = useDefaultRole();

useEffect(() => {
if (field.value || !defaultRole) {
return;
}

// Skip if the default role from org settings is not in the current role set
// This will eventually be returned by the roles endpoint, and `organizationSettings.domains.defaultRole` will be deprecated
const defaultRoleExists = options?.some(option => option.value === defaultRole);
if (!defaultRoleExists) {
return;
}

field.setValue(defaultRole);
}, [defaultRole, options, field]);

return (
<Form.ControlRow elementId={field.id}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,59 @@ describe('InviteMembersPage', () => {
await waitFor(() => expect(getByRole('button', { name: /select role/i })).toBeInTheDocument());
});

it('enables selecting other options if default role is not available', async () => {
const { wrapper, fixtures } = await createFixtures(f => {
f.withOrganizations();
f.withOrganizationDomains(undefined, 'mydefaultrole');
f.withUser({
email_addresses: ['[email protected]'],
organization_memberships: [{ name: 'Org1', role: 'admin' }],
});
});

fixtures.clerk.organization?.getInvitations.mockRejectedValue(null);
fixtures.clerk.organization?.getRoles.mockResolvedValue({
total_count: 1,
data: [
{
pathRoot: '',
reload: vi.fn(),
id: 'member',
key: 'member',
name: 'member',
description: '',
permissions: [],
createdAt: new Date(),
updatedAt: new Date(),
},
{
pathRoot: '',
reload: vi.fn(),
id: 'admin',
key: 'admin',
name: 'admin',
description: '',
permissions: [],
createdAt: new Date(),
updatedAt: new Date(),
},
],
});

fixtures.clerk.organization?.inviteMembers.mockResolvedValueOnce([{}] as OrganizationInvitationResource[]);
const { findByText, getByRole, userEvent, getByTestId } = render(
<Action.Root>
<InviteMembersScreen />
</Action.Root>,
{ wrapper },
);
await userEvent.type(getByTestId('tag-input'), '[email protected],');
await waitFor(() => expect(getByRole('button', { name: /select role/i })).toBeInTheDocument());
await userEvent.click(getByRole('button', { name: /select role/i }));
await userEvent.click(await findByText(/admin/i));
await waitFor(() => expect(getByRole('button', { name: 'Send invitations' })).not.toBeDisabled());
});

it('enables send button with default role once email address has been entered', async () => {
const defaultRole = 'mydefaultrole';

Expand Down Expand Up @@ -306,7 +359,9 @@ describe('InviteMembersPage', () => {

expect(getByRole('button', { name: 'Send invitations' })).toBeDisabled();
await userEvent.type(getByTestId('tag-input'), '[email protected],');
expect(getByRole('button', { name: 'Send invitations' })).not.toBeDisabled();
await waitFor(() => {
expect(getByRole('button', { name: 'Send invitations' })).not.toBeDisabled();
});
await userEvent.click(getByRole('button', { name: /mydefaultrole/i }));
});
});
Expand Down
Loading