Skip to content

Commit

Permalink
feat(clerk-js,shared): getMemberships support for paginated responses…
Browse files Browse the repository at this point in the history
… + useOrganization adds `memberships` (#1708)

* feat(clerk-js): `getMemberships` support for paginated responses

* feat(shared): Deprecate `membershipList` useOrganization and add `memberships`

* fix(types): Typo in types
  • Loading branch information
panteliselef authored Sep 14, 2023
1 parent 3b55f01 commit 30bb9ec
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-wolves-tie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Organization.getMemberships now supports paginated responses by passing `{paginated:true}`
5 changes: 5 additions & 0 deletions .changeset/hot-chairs-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/shared': patch
---

Deprecate `membershipList` in favor of `memberships` that supports paginated responses
33 changes: 27 additions & 6 deletions packages/clerk-js/src/core/resources/Organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
CreateOrganizationParams,
GetDomainsParams,
GetMembershipRequestParams,
GetMembershipsParams,
GetMemberships,
GetPendingInvitationsParams,
InviteMemberParams,
InviteMembersParams,
Expand Down Expand Up @@ -156,17 +156,38 @@ export class Organization extends BaseResource implements OrganizationResource {
return OrganizationDomain.create(this.id, { name });
};

getMemberships = async (getMemberhipsParams?: GetMembershipsParams): Promise<OrganizationMembership[]> => {
getMemberships: GetMemberships = async getMembershipsParams => {
const isDeprecatedParams = typeof getMembershipsParams === 'undefined' || !getMembershipsParams?.paginated;
return await BaseResource._fetch({
path: `/organizations/${this.id}/memberships`,
method: 'GET',
search: getMemberhipsParams as any,
search: isDeprecatedParams
? getMembershipsParams
: (convertPageToOffset(getMembershipsParams as unknown as any) as any),
})
.then(res => {
const members = res?.response as unknown as OrganizationMembershipJSON[];
return members.map(member => new OrganizationMembership(member));
if (isDeprecatedParams) {
const organizationMembershipsJSON = res?.response as unknown as OrganizationMembershipJSON[];
return organizationMembershipsJSON.map(orgMem => new OrganizationMembership(orgMem)) as any;
}

const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>;

return {
total_count,
data: suggestions.map(suggestion => new OrganizationMembership(suggestion)),
} as any;
})
.catch(() => []);
.catch(() => {
if (isDeprecatedParams) {
return [];
}
return {
total_count: 0,
data: [],
};
});
};

getPendingInvitations = async (
Expand Down
61 changes: 61 additions & 0 deletions packages/shared/src/hooks/useOrganization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
OrganizationResource,
} from '@clerk/types';
import type { ClerkPaginatedResponse } from '@clerk/types';
import type { GetMembersParams } from '@clerk/types';

import { disableSWRDevtools } from './clerk-swr';
disableSWRDevtools();
Expand All @@ -21,6 +22,9 @@ import { usePagesOrInfinite, useWithSafeValues } from './usePagesOrInfinite';

type UseOrganizationParams = {
invitationList?: GetPendingInvitationsParams;
/**
* @deprecated Use members instead
*/
membershipList?: GetMembershipsParams;
domains?:
| true
Expand All @@ -34,35 +38,53 @@ type UseOrganizationParams = {
infinite?: boolean;
keepPreviousData?: boolean;
});
memberships?:
| true
| (GetMembersParams & {
infinite?: boolean;
keepPreviousData?: boolean;
});
};

type UseOrganizationReturn =
| {
isLoaded: false;
organization: undefined;
invitationList: undefined;
/**
* @deprecated Use members instead
*/
membershipList: undefined;
membership: undefined;
domains: PaginatedResourcesWithDefault<OrganizationDomainResource>;
membershipRequests: PaginatedResourcesWithDefault<OrganizationMembershipRequestResource>;
memberships: PaginatedResourcesWithDefault<OrganizationMembershipResource>;
}
| {
isLoaded: true;
organization: OrganizationResource;
invitationList: undefined;
/**
* @deprecated Use members instead
*/
membershipList: undefined;
membership: undefined;
domains: PaginatedResourcesWithDefault<OrganizationDomainResource>;
membershipRequests: PaginatedResourcesWithDefault<OrganizationMembershipRequestResource>;
memberships: PaginatedResourcesWithDefault<OrganizationMembershipResource>;
}
| {
isLoaded: boolean;
organization: OrganizationResource | null;
invitationList: OrganizationInvitationResource[] | null | undefined;
/**
* @deprecated Use members instead
*/
membershipList: OrganizationMembershipResource[] | null | undefined;
membership: OrganizationMembershipResource | null | undefined;
domains: PaginatedResources<OrganizationDomainResource> | null;
membershipRequests: PaginatedResources<OrganizationMembershipRequestResource> | null;
memberships: PaginatedResources<OrganizationMembershipResource> | null;
};

type UseOrganization = (params?: UseOrganizationParams) => UseOrganizationReturn;
Expand All @@ -88,6 +110,7 @@ export const useOrganization: UseOrganization = params => {
membershipList: membershipListParams,
domains: domainListParams,
membershipRequests: membershipRequestsListParams,
memberships: membersListParams,
} = params || {};
const { organization, lastOrganizationMember, lastOrganizationInvitation } = useOrganizationContext();
const session = useSessionContext();
Expand All @@ -108,6 +131,14 @@ export const useOrganization: UseOrganization = params => {
infinite: false,
});

const membersSafeValues = useWithSafeValues(membersListParams, {
initialPage: 1,
pageSize: 10,
role: ['admin'],
keepPreviousData: false,
infinite: false,
});

const clerk = useClerkInstanceContext();

const shouldFetch = !!(clerk.loaded && session && organization);
Expand All @@ -130,6 +161,15 @@ export const useOrganization: UseOrganization = params => {
status: membershipRequestSafeValues.status,
};

const membersParams =
typeof membersListParams === 'undefined'
? undefined
: {
initialPage: membersSafeValues.initialPage,
pageSize: membersSafeValues.pageSize,
role: membersSafeValues.role,
};

const domains = usePagesOrInfinite<GetDomainsParams, ClerkPaginatedResponse<OrganizationDomainResource>>(
{
...domainParams,
Expand Down Expand Up @@ -165,6 +205,23 @@ export const useOrganization: UseOrganization = params => {
},
);

const memberships = usePagesOrInfinite<GetMembersParams, ClerkPaginatedResponse<OrganizationMembershipResource>>(
{
...membersParams,
paginated: true,
} as any,
organization?.getMemberships as unknown as any,
{
keepPreviousData: membersSafeValues.keepPreviousData,
infinite: membersSafeValues.infinite,
enabled: !!membersParams,
},
{
type: 'members',
organizationId: organization?.id,
},
);

// Some gymnastics to adhere to the rules of hooks
// We need to make sure useSWR is called on every render
const pendingInvitations = !clerk.loaded
Expand Down Expand Up @@ -206,6 +263,7 @@ export const useOrganization: UseOrganization = params => {
membership: undefined,
domains: undefinedPaginatedResource,
membershipRequests: undefinedPaginatedResource,
memberships: undefinedPaginatedResource,
};
}

Expand All @@ -218,6 +276,7 @@ export const useOrganization: UseOrganization = params => {
membership: null,
domains: null,
membershipRequests: null,
memberships: null,
};
}

Expand All @@ -231,6 +290,7 @@ export const useOrganization: UseOrganization = params => {
membership: undefined,
domains: undefinedPaginatedResource,
membershipRequests: undefinedPaginatedResource,
memberships: undefinedPaginatedResource,
};
}

Expand All @@ -246,6 +306,7 @@ export const useOrganization: UseOrganization = params => {
},
domains,
membershipRequests,
memberships,
};
};

Expand Down
32 changes: 29 additions & 3 deletions packages/types/src/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface OrganizationResource extends ClerkResource {
createdAt: Date;
updatedAt: Date;
update: (params: UpdateOrganizationParams) => Promise<OrganizationResource>;
getMemberships: (params?: GetMembershipsParams) => Promise<OrganizationMembershipResource[]>;
getMemberships: GetMemberships;
getPendingInvitations: (params?: GetPendingInvitationsParams) => Promise<OrganizationInvitationResource[]>;
getDomains: (params?: GetDomainsParams) => Promise<ClerkPaginatedResponse<OrganizationDomainResource>>;
getMembershipRequests: (
Expand All @@ -60,14 +60,30 @@ export interface OrganizationResource extends ClerkResource {
setLogo: (params: SetOrganizationLogoParams) => Promise<OrganizationResource>;
}

/**
* @deprecated use GetMembersParams
*/
export type GetMembershipsParams = {
role?: MembershipRole[];
} & ClerkPaginationParams;

export type GetMembersParams = {
/**
* This is the starting point for your fetched results. The initial value persists between re-renders
*/
initialPage?: number;
/**
* Maximum number of items returned per request. The initial value persists between re-renders
*/
pageSize?: number;

role?: MembershipRole[];
};

export type GetPendingInvitationsParams = ClerkPaginationParams;
export type GetDomainsParams = {
/**
* This the starting point for your fetched results. The initial value persists between re-renders
* This is the starting point for your fetched results. The initial value persists between re-renders
*/
initialPage?: number;
/**
Expand All @@ -80,7 +96,7 @@ export type GetDomainsParams = {

export type GetMembershipRequestParams = {
/**
* This the starting point for your fetched results. The initial value persists between re-renders
* This is the starting point for your fetched results. The initial value persists between re-renders
*/
initialPage?: number;
/**
Expand Down Expand Up @@ -119,3 +135,13 @@ export interface UpdateOrganizationParams {
export interface SetOrganizationLogoParams {
file: Blob | File | string | null;
}

type MembersParams = (GetMembershipsParams | GetMembersParams) & {
paginated?: boolean;
};

export type GetMemberships = <T extends MembersParams>(
params?: T,
) => T['paginated'] extends true
? Promise<ClerkPaginatedResponse<OrganizationMembershipResource>>
: Promise<OrganizationMembershipResource[]>;

0 comments on commit 30bb9ec

Please sign in to comment.