Skip to content

Commit

Permalink
chore(clerk-js): Use userMemberships instead of organizationList
Browse files Browse the repository at this point in the history
…inside `OrganizationSwitcher` (#2118)
  • Loading branch information
panteliselef authored Nov 13, 2023
1 parent 12b26ed commit 2705246
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-tables-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Use `userMemberships` instead of `organizationList` inside `<OrganizationSwitcher/>`.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { OrganizationResource } from '@clerk/types';
import React from 'react';

import { InfiniteListSpinner } from '../../common';
import {
useCoreOrganization,
useCoreOrganizationList,
Expand All @@ -9,25 +10,54 @@ import {
} from '../../contexts';
import { Box, descriptors, localizationKeys } from '../../customizables';
import { OrganizationPreview, PersonalWorkspacePreview, PreviewButton } from '../../elements';
import { useInView } from '../../hooks';
import { SwitchArrows } from '../../icons';
import { common } from '../../styledSystem';
import { organizationListParams } from './utils';

export type UserMembershipListProps = {
onPersonalWorkspaceClick: React.MouseEventHandler;
onOrganizationClick: (org: OrganizationResource) => unknown;
};

const useFetchMemberships = () => {
const { userMemberships } = useCoreOrganizationList({
userMemberships: organizationListParams.userMemberships,
});

const { ref } = useInView({
threshold: 0,
onChange: inView => {
if (!inView) {
return;
}
if (userMemberships.hasNextPage) {
userMemberships.fetchNext?.();
}
},
});

return {
userMemberships,
ref,
};
};
export const UserMembershipList = (props: UserMembershipListProps) => {
const { onPersonalWorkspaceClick, onOrganizationClick } = props;

const { hidePersonal } = useOrganizationSwitcherContext();
const { organization: currentOrg } = useCoreOrganization();
const { organizationList } = useCoreOrganizationList();
const { ref, userMemberships } = useFetchMemberships();
const user = useCoreUser();

const otherOrgs = (organizationList || []).map(e => e.organization).filter(o => o.id !== currentOrg?.id);
const otherOrgs = ((userMemberships.count || 0) > 0 ? userMemberships.data || [] : [])
.map(e => e.organization)
.filter(o => o.id !== currentOrg?.id);

const { username, primaryEmailAddress, primaryPhoneNumber, ...userWithoutIdentifiers } = user;

const { isLoading, hasNextPage } = userMemberships;

return (
<Box
sx={t => ({
Expand Down Expand Up @@ -71,6 +101,7 @@ export const UserMembershipList = (props: UserMembershipListProps) => {
/>
</PreviewButton>
))}
{(hasNextPage || isLoading) && <InfiniteListSpinner ref={ref} />}
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { describe } from '@jest/globals';
import { act, render, runFakeTimers, waitFor } from '../../../../testUtils';
import { bindCreateFixtures } from '../../../utils/test/createFixtures';
import { OrganizationSwitcher } from '../OrganizationSwitcher';
import { createFakeUserOrganizationInvitation, createFakeUserOrganizationSuggestion } from './utlis';
import {
createFakeUserOrganizationInvitation,
createFakeUserOrganizationMembership,
createFakeUserOrganizationSuggestion,
} from './utlis';

const { createFixtures } = bindCreateFixtures('OrganizationSwitcher');

Expand Down Expand Up @@ -130,11 +134,43 @@ describe('OrganizationSwitcher', () => {
});

it('lists all organizations the user belongs to', async () => {
const { wrapper, props } = await createFixtures(f => {
const { wrapper, props, fixtures } = await createFixtures(f => {
f.withOrganizations();
f.withUser({ email_addresses: ['test@clerk.com'], organization_memberships: ['Org1', 'Org2'] });
});

fixtures.clerk.user?.getOrganizationMemberships.mockReturnValueOnce(
Promise.resolve({
data: [
createFakeUserOrganizationMembership({
id: '1',
organization: {
id: '1',
name: 'Org1',
slug: 'org1',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
createFakeUserOrganizationMembership({
id: '2',
organization: {
id: '2',
name: 'Org2',
slug: 'org2',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
],
total_count: 2,
}),
);

props.setProps({ hidePersonal: false });
const { getAllByText, getByText, getByRole, userEvent } = render(<OrganizationSwitcher />, { wrapper });
await userEvent.click(getByRole('button'));
Expand Down Expand Up @@ -313,6 +349,39 @@ describe('OrganizationSwitcher', () => {
create_organization_enabled: false,
});
});

fixtures.clerk.user?.getOrganizationMemberships.mockReturnValueOnce(
Promise.resolve({
data: [
createFakeUserOrganizationMembership({
id: '1',
organization: {
id: '1',
name: 'Org1',
slug: 'org1',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
createFakeUserOrganizationMembership({
id: '2',
organization: {
id: '2',
name: 'Org2',
slug: 'org2',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
],
total_count: 2,
}),
);

fixtures.clerk.setActive.mockReturnValueOnce(Promise.resolve());

props.setProps({ hidePersonal: true });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { OrganizationResource } from '@clerk/types';
import React from 'react';

import { InfiniteListSpinner } from '../../common';
import {
useCoreOrganization,
useCoreOrganizationList,
Expand All @@ -9,26 +10,54 @@ import {
} from '../../contexts';
import { Box, descriptors, localizationKeys } from '../../customizables';
import { OrganizationPreview, PersonalWorkspacePreview, PreviewButton } from '../../elements';
import { useInView } from '../../hooks';
import { SwitchArrows } from '../../icons';
import { common } from '../../styledSystem';
import { organizationListParams } from './utils';

export type UserMembershipListProps = {
onPersonalWorkspaceClick: React.MouseEventHandler;
onOrganizationClick: (org: OrganizationResource) => unknown;
};

const useFetchMemberships = () => {
const { userMemberships } = useCoreOrganizationList({
userMemberships: organizationListParams.userMemberships,
});

const { ref } = useInView({
threshold: 0,
onChange: inView => {
if (!inView) {
return;
}
if (userMemberships.hasNextPage) {
userMemberships.fetchNext?.();
}
},
});

return {
userMemberships,
ref,
};
};
export const UserMembershipList = (props: UserMembershipListProps) => {
const { onPersonalWorkspaceClick, onOrganizationClick } = props;

const { hidePersonal } = useOrganizationSwitcherContext();
const { organization: currentOrg } = useCoreOrganization();
const { organizationList } = useCoreOrganizationList();
const { ref, userMemberships } = useFetchMemberships();
const user = useCoreUser();

const otherOrgs = (organizationList || []).map(e => e.organization).filter(o => o.id !== currentOrg?.id);
const otherOrgs = ((userMemberships.count || 0) > 0 ? userMemberships.data || [] : [])
.map(e => e.organization)
.filter(o => o.id !== currentOrg?.id);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { username, primaryEmailAddress, primaryPhoneNumber, ...userWithoutIdentifiers } = user;

const { isLoading, hasNextPage } = userMemberships;

return (
<Box
sx={t => ({
Expand Down Expand Up @@ -72,6 +101,7 @@ export const UserMembershipList = (props: UserMembershipListProps) => {
/>
</PreviewButton>
))}
{(hasNextPage || isLoading) && <InfiniteListSpinner ref={ref} />}
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { describe } from '@jest/globals';
import { act, render, runFakeTimers, waitFor } from '../../../../testUtils';
import { bindCreateFixtures } from '../../../utils/test/createFixtures';
import { OrganizationSwitcher } from '../OrganizationSwitcher';
import { createFakeUserOrganizationInvitation, createFakeUserOrganizationSuggestion } from './utlis';
import {
createFakeUserOrganizationInvitation,
createFakeUserOrganizationMembership,
createFakeUserOrganizationSuggestion,
} from './utlis';

const { createFixtures } = bindCreateFixtures('OrganizationSwitcher');

Expand Down Expand Up @@ -130,11 +134,43 @@ describe('OrganizationSwitcher', () => {
});

it('lists all organizations the user belongs to', async () => {
const { wrapper, props } = await createFixtures(f => {
const { wrapper, props, fixtures } = await createFixtures(f => {
f.withOrganizations();
f.withUser({ email_addresses: ['test@clerk.com'], organization_memberships: ['Org1', 'Org2'] });
});

fixtures.clerk.user?.getOrganizationMemberships.mockReturnValueOnce(
Promise.resolve({
data: [
createFakeUserOrganizationMembership({
id: '1',
organization: {
id: '1',
name: 'Org1',
slug: 'org1',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
createFakeUserOrganizationMembership({
id: '2',
organization: {
id: '2',
name: 'Org2',
slug: 'org2',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
],
total_count: 2,
}),
);

props.setProps({ hidePersonal: false });
const { getAllByText, getByText, getByRole, userEvent } = render(<OrganizationSwitcher />, { wrapper });
await userEvent.click(getByRole('button'));
Expand Down Expand Up @@ -313,6 +349,39 @@ describe('OrganizationSwitcher', () => {
create_organization_enabled: false,
});
});

fixtures.clerk.user?.getOrganizationMemberships.mockReturnValueOnce(
Promise.resolve({
data: [
createFakeUserOrganizationMembership({
id: '1',
organization: {
id: '1',
name: 'Org1',
slug: 'org1',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
createFakeUserOrganizationMembership({
id: '2',
organization: {
id: '2',
name: 'Org2',
slug: 'org2',
membersCount: 1,
adminDeleteEnabled: false,
maxAllowedMemberships: 1,
pendingInvitationsCount: 1,
},
}),
],
total_count: 2,
}),
);

fixtures.clerk.setActive.mockReturnValueOnce(Promise.resolve());

props.setProps({ hidePersonal: true });
Expand Down

0 comments on commit 2705246

Please sign in to comment.