Skip to content

Commit 5fbc495

Browse files
authored
Merge pull request #388 from auth0/feat/refactor-assignrole-removefromorg-duplicates
feat: refactor duplicate mutations for assign role and remove from org
2 parents f0f1a37 + 65625da commit 5fbc495

6 files changed

Lines changed: 26 additions & 84 deletions

File tree

packages/react/src/components/auth0/my-organization/__tests__/organization-member-detail.test.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComponentAction } from '@auth0/universal-components-core';
2-
import { memberManagementQueryKeys } from '@auth0/universal-components-core';
2+
import { memberManagementQueryKeys, memberDetailQueryKeys } from '@auth0/universal-components-core';
33
import { screen, waitFor } from '@testing-library/react';
44
import userEvent from '@testing-library/user-event';
55
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
@@ -655,9 +655,11 @@ describe('OrganizationMemberDetail', () => {
655655
await waitFor(() => {
656656
expect(apiService.organization.members.roles.assign).toHaveBeenCalled();
657657
});
658-
659658
expect(invalidateQueriesSpy).toHaveBeenCalledWith({
660-
queryKey: memberManagementQueryKeys.members(),
659+
queryKey: memberManagementQueryKeys.all,
660+
});
661+
expect(invalidateQueriesSpy).toHaveBeenCalledWith({
662+
queryKey: memberDetailQueryKeys.memberRoles(mockMember.user_id ?? ''),
661663
});
662664
});
663665

packages/react/src/components/auth0/my-organization/organization-member-detail.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ export function OrganizationMemberDetailView(
189189
customMessages={customMessages}
190190
organizationName={props.organizationDisplayName}
191191
memberName={props.member?.name}
192+
selectedMember={props.member}
192193
memberRoles={props.memberRoles}
193194
availableRoles={props.availableRoles}
194195
selectedRoles={props.selectedRoles}
@@ -213,6 +214,7 @@ export function OrganizationMemberDetailView(
213214
isOpen={modalState.type === 'removeFromOrganization'}
214215
isLoading={isRemovingFromOrganization}
215216
memberName={props.member?.name}
217+
memberUserId={props.member?.user_id}
216218
organizationName={props.organizationDisplayName}
217219
customMessages={customMessages}
218220
onClose={closeModal}

packages/react/src/components/auth0/my-organization/shared/member-management/organization-member-detail/organization-member-roles-tab.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ export function OrganizationMemberEditRolesTab({
165165
customMessages,
166166
organizationName,
167167
memberName,
168+
selectedMember,
168169
memberRoles,
169170
availableRoles,
170171
selectedRoles,
@@ -217,6 +218,7 @@ export function OrganizationMemberEditRolesTab({
217218
isLoading={isAssigningRoles || isFetchingAvailableRoles}
218219
availableRoles={availableRoles}
219220
assignedRoles={memberRoles}
221+
selectedMember={selectedMember}
220222
customMessages={customMessages}
221223
onClose={onAssignRolesCancel}
222224
onAssign={onAssignRolesSubmit}

packages/react/src/hooks/my-organization/shared/services/use-member-detail-service.ts

Lines changed: 5 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ export function useMemberDetailService(
6363
enabled: !!coreClient && isValidUserId && memberQuery.isSuccess,
6464
});
6565

66-
const { rolesQuery } = useMemberManagementService({});
66+
const { rolesQuery, assignRolesMutation, removeFromOrganizationMutation } =
67+
useMemberManagementService({
68+
assignRolesAction,
69+
removeFromOrganizationAction,
70+
});
6771

6872
const organizationQuery = useQuery({
6973
queryKey: memberDetailQueryKeys.organization,
@@ -74,79 +78,6 @@ export function useMemberDetailService(
7478
enabled: !!coreClient,
7579
});
7680

77-
const removeFromOrganizationMutation = useMutation({
78-
mutationFn: async (_args: {
79-
memberId?: string;
80-
memberName?: string;
81-
organizationName?: string;
82-
}) => {
83-
if (!userId) throw new Error('userId is required');
84-
if (
85-
removeFromOrganizationAction?.onBefore &&
86-
!removeFromOrganizationAction.onBefore(userId)
87-
) {
88-
throw new Error('Remove from org cancelled by onBefore');
89-
}
90-
await coreClient!
91-
.getMyOrganizationApiClient()
92-
.organization.memberships.deleteMemberships({ members: [userId] });
93-
},
94-
onSuccess: (_, { memberName, organizationName }) => {
95-
removeFromOrganizationAction?.onAfter?.(userId);
96-
showToast({
97-
type: 'success',
98-
message: t('member.detail.actions.remove_from_organization.success', {
99-
memberName: memberName,
100-
organizationName: organizationName,
101-
}),
102-
});
103-
queryClient.invalidateQueries({ queryKey: memberManagementQueryKeys.members() });
104-
},
105-
onError: (error) => {
106-
handleError(error, {
107-
fallbackMessage: t('member.detail.error.remove_from_organization_failed'),
108-
});
109-
},
110-
});
111-
112-
const assignRolesMutation = useMutation({
113-
mutationFn: async ({ roleIds, memberRoles }: { roleIds: string[]; memberRoles: Role[] }) => {
114-
if (!userId) throw new Error('userId is required');
115-
const validationResult = validateRequestRoleForMember(t, roleIds, memberRoles, true);
116-
if (validationResult?.aborted) {
117-
return validationResult;
118-
}
119-
120-
if (assignRolesAction?.onBefore && !assignRolesAction.onBefore({ userId, roleIds })) {
121-
throw new Error('Assign roles cancelled by onBefore');
122-
}
123-
await coreClient!
124-
.getMyOrganizationApiClient()
125-
.organization.members.roles.assign(userId, { role_ids: roleIds });
126-
assignRolesAction?.onAfter?.({ userId, roleIds });
127-
return { aborted: false } as const;
128-
},
129-
onSuccess: (result, { roleIds }) => {
130-
if (result?.aborted) return;
131-
const allRoles = queryClient.getQueryData<Role[]>(memberManagementQueryKeys.roles()) ?? [];
132-
const newRoles = allRoles.filter((r) => roleIds.includes(r.id));
133-
queryClient.setQueryData<Role[]>(memberDetailQueryKeys.memberRoles(userId), (old) => [
134-
...(old ?? []),
135-
...newRoles,
136-
]);
137-
const assignKey =
138-
roleIds.length === 1
139-
? 'member.detail.roles.assign_modal.success'
140-
: 'member.detail.roles.assign_modal.success_plural';
141-
showToast({ type: 'success', message: t(assignKey) });
142-
queryClient.invalidateQueries({ queryKey: memberDetailQueryKeys.memberRoles(userId) });
143-
queryClient.invalidateQueries({ queryKey: memberManagementQueryKeys.members() });
144-
},
145-
onError: (error) => {
146-
handleError(error, { fallbackMessage: t('member.detail.error.assign_role_failed') });
147-
},
148-
});
149-
15081
const removeRolesMutation = useMutation({
15182
mutationFn: async (roles: Role[]) => {
15283
if (!userId) throw new Error('userId is required');

packages/react/src/hooks/my-organization/use-member-detail.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export function useOrganizationMemberDetail(
8888
}, []);
8989

9090
const handleRemoveFromOrganizationConfirm = React.useCallback(
91-
(userId?: string, memberName?: string, organizationName?: string) => {
91+
(userId?: string | null, memberName?: string, organizationName?: string) => {
9292
removeFromOrganizationMutation.mutate(
9393
{ userId, memberName, organizationName },
9494
{
@@ -103,9 +103,9 @@ export function useOrganizationMemberDetail(
103103
);
104104

105105
const handleAssignRolesSubmit = React.useCallback(
106-
(roleIds: string[], memberRoles: Role[]) => {
106+
(roleIds: string[], memberRoles: Role[], userId?: string | null) => {
107107
assignRolesMutation.mutate(
108-
{ roleIds, memberRoles },
108+
{ roleIds, memberRoles, userId },
109109
{
110110
onSuccess: (result) => {
111111
if (result?.aborted) return;

packages/react/src/types/my-organization/member-management/organization-member-detail-types.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface MemberDetailServiceResult {
2424
removeFromOrganizationMutation: UseMutationResult<
2525
void,
2626
Error,
27-
{ userId?: string; memberName?: string; organizationName?: string }
27+
{ userId?: string | null; memberName?: string; organizationName?: string }
2828
>;
2929
assignRolesMutation: UseMutationResult<
3030
{ aborted: boolean },
@@ -74,8 +74,12 @@ export interface UseOrganizationMemberDetailResult {
7474
handleBack: () => void;
7575
openModal: (state: MemberDetailModalState) => void;
7676
closeModal: () => void;
77-
handleRemoveFromOrganizationConfirm: (memberName?: string, organizationName?: string) => void;
78-
handleAssignRolesSubmit: (roleIds: string[], memberRoles: Role[]) => void;
77+
handleRemoveFromOrganizationConfirm: (
78+
userId?: string | null,
79+
memberName?: string,
80+
organizationName?: string,
81+
) => void;
82+
handleAssignRolesSubmit: (roleIds: string[], memberRoles: Role[], userId?: string | null) => void;
7983
handleRemoveRolesCancel: () => void;
8084
handleRemoveRolesConfirm: () => void;
8185
}
@@ -188,6 +192,7 @@ export interface OrganizationMemberEditRolesTabProps {
188192
customMessages?: Partial<OrganizationMemberDetailMessages>;
189193
organizationName?: string;
190194
memberName?: string;
195+
selectedMember?: OrgMember | null;
191196
memberRoles: Role[];
192197
availableRoles: Role[];
193198
selectedRoles: Role[];
@@ -200,7 +205,7 @@ export interface OrganizationMemberEditRolesTabProps {
200205
onSelectedRolesChange: (roles: Role[]) => void;
201206
onAssignRolesClick: () => void;
202207
onAssignRolesCancel: () => void;
203-
onAssignRolesSubmit: (roleIds: string[], memberRoles: Role[]) => void;
208+
onAssignRolesSubmit: (roleIds: string[], memberRoles: Role[], userId?: string | null) => void;
204209
onRemoveRolesClick: (roles: Role[]) => void;
205210
onRemoveRolesCancel: () => void;
206211
onRemoveRolesConfirm: () => void;

0 commit comments

Comments
 (0)