diff --git a/.changeset/light-pumas-push.md b/.changeset/light-pumas-push.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/light-pumas-push.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/rotten-rules-argue.md b/.changeset/rotten-rules-argue.md new file mode 100644 index 0000000000..4b22bdb902 --- /dev/null +++ b/.changeset/rotten-rules-argue.md @@ -0,0 +1,10 @@ +--- +'@clerk/localizations': patch +'@clerk/clerk-js': patch +'@clerk/types': patch +--- + +A OrganizationMembershipRequest can now be rejected + +- New `OrganizationMembershipRequest.reject` method alongside `accept` +- As an organization admin, navigate to `Organization Profile` > `Members` > `Requests`. You can now reject a request from the table. diff --git a/packages/clerk-js/src/core/resources/OrganizationDomain.ts b/packages/clerk-js/src/core/resources/OrganizationDomain.ts index 6fb81651da..faf537f315 100644 --- a/packages/clerk-js/src/core/resources/OrganizationDomain.ts +++ b/packages/clerk-js/src/core/resources/OrganizationDomain.ts @@ -5,7 +5,7 @@ import type { OrganizationDomainVerification, OrganizationEnrollmentMode, PrepareAffiliationVerificationParams, - UpdateOrganizationDomainParams, + UpdateEnrollmentModeParams, } from '@clerk/types'; import { unixEpochToDate } from '../../utils/date'; @@ -57,10 +57,9 @@ export class OrganizationDomain extends BaseResource implements OrganizationDoma }); }; - update = (params: UpdateOrganizationDomainParams): Promise => { - return this._basePatch({ - method: 'PATCH', - path: `/organizations/${this.organizationId}/domains/${this.id}`, + updateEnrollmentMode = (params: UpdateEnrollmentModeParams): Promise => { + return this._basePost({ + path: `/organizations/${this.organizationId}/domains/${this.id}/update_enrollment_mode`, body: params, }); }; diff --git a/packages/clerk-js/src/core/resources/OrganizationMembershipRequest.ts b/packages/clerk-js/src/core/resources/OrganizationMembershipRequest.ts index 1beb70211e..071315c426 100644 --- a/packages/clerk-js/src/core/resources/OrganizationMembershipRequest.ts +++ b/packages/clerk-js/src/core/resources/OrganizationMembershipRequest.ts @@ -23,6 +23,12 @@ export class OrganizationMembershipRequest extends BaseResource implements Organ }); }; + reject = async (): Promise => { + return await this._basePost({ + path: `/organizations/${this.organizationId}/membership_requests/${this.id}/reject`, + }); + }; + protected fromJSON(data: OrganizationMembershipRequestJSON | null): this { if (data) { this.id = data.id; diff --git a/packages/clerk-js/src/core/resources/__snapshots__/OrganizationDomain.test.ts.snap b/packages/clerk-js/src/core/resources/__snapshots__/OrganizationDomain.test.ts.snap index 85a8c0eb05..bfb447ee10 100644 --- a/packages/clerk-js/src/core/resources/__snapshots__/OrganizationDomain.test.ts.snap +++ b/packages/clerk-js/src/core/resources/__snapshots__/OrganizationDomain.test.ts.snap @@ -11,7 +11,7 @@ OrganizationDomain { "organizationId": "test_org_id", "pathRoot": "", "prepareAffiliationVerification": [Function], - "update": [Function], + "updateEnrollmentMode": [Function], "verification": null, } `; @@ -27,7 +27,7 @@ OrganizationDomain { "organizationId": "test_org_id", "pathRoot": "", "prepareAffiliationVerification": [Function], - "update": [Function], + "updateEnrollmentMode": [Function], "verification": { "attempts": 1, "expiresAt": 1970-01-01T00:00:12.345Z, diff --git a/packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembershipRequest.test.ts.snap b/packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembershipRequest.test.ts.snap index b1d4f1c218..9f0583a730 100644 --- a/packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembershipRequest.test.ts.snap +++ b/packages/clerk-js/src/core/resources/__snapshots__/OrganizationMembershipRequest.test.ts.snap @@ -16,6 +16,7 @@ OrganizationMembershipRequest { "profileImageUrl": "test_url", "userId": undefined, }, + "reject": [Function], "status": "pending", "updatedAt": 1970-01-01T00:00:05.678Z, } diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/InvitedMembersList.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/InvitedMembersList.tsx index 674d5b22e2..17e96f12bf 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/InvitedMembersList.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/InvitedMembersList.tsx @@ -66,7 +66,6 @@ const InvitationRow = (props: { invitation: OrganizationInvitationResource; onRe diff --git a/packages/clerk-js/src/ui/components/OrganizationProfile/RequestToJoinList.tsx b/packages/clerk-js/src/ui/components/OrganizationProfile/RequestToJoinList.tsx index 432562f86e..d78a6e3d0f 100644 --- a/packages/clerk-js/src/ui/components/OrganizationProfile/RequestToJoinList.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationProfile/RequestToJoinList.tsx @@ -2,7 +2,7 @@ import type { OrganizationMembershipRequestResource } from '@clerk/types'; import { useCoreOrganization } from '../../contexts'; import { Button, Flex, localizationKeys, Td } from '../../customizables'; -import { useCardState, UserPreview } from '../../elements'; +import { useCardState, UserPreview, withCardStateProvider } from '../../elements'; import { handleError } from '../../utils'; import { DataTable, RowContainer } from './MemberListTable'; @@ -15,82 +15,101 @@ export const RequestToJoinList = () => { }, }); - const mutateSwrState = () => { - const unstable__mutate = (membershipRequests as any).unstable__mutate; - if (unstable__mutate && typeof unstable__mutate === 'function') { - unstable__mutate(); - } - }; - if (!organization) { return null; } - const approve = (request: OrganizationMembershipRequestResource) => () => { - return card - .runAsync(request.accept) - .then(mutateSwrState) - .catch(err => handleError(err, [], card.setError)); - }; - return ( null)} itemCount={membershipRequests?.count ?? 0} itemsPerPage={ITEMS_PER_PAGE} - isLoading={membershipRequests?.isFetching} + isLoading={membershipRequests?.isLoading} emptyStateLocalizationKey={localizationKeys('organizationProfile.membersPage.requestsTab.table__emptyRow')} headers={[ localizationKeys('organizationProfile.membersPage.activeMembersTab.tableHeader__user'), localizationKeys('organizationProfile.membersPage.requestsTab.tableHeader__requested'), localizationKeys('organizationProfile.membersPage.activeMembersTab.tableHeader__actions'), ]} - rows={(membershipRequests?.data || []).map(i => ( + rows={(membershipRequests?.data || []).map(request => ( ))} /> ); }; -const RequestRow = (props: { request: OrganizationMembershipRequestResource; onAccept: () => unknown }) => { - const { request, onAccept } = props; +const RequestRow = withCardStateProvider( + (props: { request: OrganizationMembershipRequestResource; onError: ReturnType['setError'] }) => { + const { request, onError } = props; + const card = useCardState(); + const { membershipRequests } = useCoreOrganization(); - return ( - - - - - {request.createdAt.toLocaleDateString()} + const mutateSwrState = () => { + const unstable__mutate = (membershipRequests as any).unstable__mutate; + if (unstable__mutate && typeof unstable__mutate === 'function') { + unstable__mutate(); + } + }; - - - - - - - ); -}; + const onAccept = () => { + return card + .runAsync(request.accept, 'accept') + .then(mutateSwrState) + .catch(err => handleError(err, [], onError)); + }; + + const onReject = () => { + return card + .runAsync(request.reject, 'reject') + .then(mutateSwrState) + .catch(err => handleError(err, [], onError)); + }; -const AcceptRejectRequestButtons = (props: { onAccept: () => unknown }) => { + return ( + + + + + {request.createdAt.toLocaleDateString()} + + + + + + ); + }, +); + +const AcceptRejectRequestButtons = (props: { onAccept: () => unknown; onReject: () => unknown }) => { const card = useCardState(); return ( - <> + +