Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import {
memberManagementQueryKeys,
OrganizationDetailsMappers,
} from '@auth0/universal-components-core';
import { useQuery, useMutation, useQueryClient, keepPreviousData } from '@tanstack/react-query';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import React from 'react';

import { showToast } from '@/components/auth0/shared/toast';
import { useCoreClient } from '@/hooks/shared/use-core-client';
import { useErrorHandler } from '@/hooks/shared/use-error-handler';
import { useTranslator } from '@/hooks/shared/use-translator';
import { getPreviousDataOption } from '@/lib/utils/tanstack-compat';
import type { CreateInvitationInput } from '@/types/my-organization/member-management/organization-invitation-table-types';
import type {
UseMemberManagementServiceOptions,
MemberManagementServiceResult,
MemberManagementSortConfig,
} from '@/types/my-organization/member-management/organization-member-management-types';

const keepPreviousDataOption = getPreviousDataOption();

const INVITATION_SORT_FIELD_MAP: Record<string, string> = {
created_at: 'created_at',
};
Expand Down Expand Up @@ -118,7 +121,7 @@ export function useMemberManagementService(
return { invitations, next };
},
enabled: !!coreClient && isInvitationsTabActive && !!invitationParams,
placeholderData: keepPreviousData,
...keepPreviousDataOption,
});

const membersQuery = useQuery({
Expand All @@ -137,7 +140,7 @@ export function useMemberManagementService(
return { members, next };
},
enabled: !!coreClient && !isInvitationsTabActive && !!memberParams,
placeholderData: keepPreviousData,
...keepPreviousDataOption,
});

const organizationQuery = useQuery({
Expand Down
9 changes: 5 additions & 4 deletions packages/react/src/hooks/my-organization/use-member-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Role } from '@auth0/universal-components-core';
import * as React from 'react';

import { useMemberDetailService } from '@/hooks/my-organization/shared/services/use-member-detail-service';
import { isMutationLoading } from '@/lib/utils/tanstack-compat';
import type {
MemberDetailModalState,
MemberDetailTab,
Expand Down Expand Up @@ -124,10 +125,10 @@ export function useOrganizationMemberDetail(
isFetchingMemberRoles: memberRolesQuery.isLoading,
isFetchingAvailableRoles: rolesQuery.isLoading || rolesQuery.isFetching,
isLoading: memberQuery.isLoading,
isRemovingFromOrg: removeFromOrgMutation.isPending,
isAssigningRoles: assignRolesMutation.isPending,
isRemovingRoles: removeRolesMutation.isPending,
removingRoleIds: removeRolesMutation.isPending ? removingRoles.map((r) => r.id) : [],
isRemovingFromOrg: isMutationLoading(removeFromOrgMutation),
isAssigningRoles: isMutationLoading(assignRolesMutation),
isRemovingRoles: isMutationLoading(removeRolesMutation),
removingRoleIds: isMutationLoading(removeRolesMutation) ? removingRoles.map((r) => r.id) : [],
modalState,

setActiveTab,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { showToast } from '@/components/auth0/shared/toast';
import { useMemberManagementService } from '@/hooks/my-organization/shared/services/use-member-management-service';
import { useCheckpointPagination } from '@/hooks/shared/use-checkpoint-pagination';
import { useTranslator } from '@/hooks/shared/use-translator';
import { isMutationLoading } from '@/lib/utils/tanstack-compat';
import type {
CreateInvitationInput,
IdentityProviderOption,
Expand Down Expand Up @@ -270,13 +271,13 @@ export function useOrganizationMemberManagement(
orgDisplayName: orgDisplayName,
isInitialLoading: invitationsQuery.isLoading || membersQuery.isLoading,
isFetchingInvitations: invitationsQuery.isFetching,
isCreatingInvitation: isMutationLoading(createInvitationMutation),
isRevokingInvitation: isMutationLoading(revokeInvitationMutation),
isResendingInvitation: isMutationLoading(resendInvitationMutation),
isFetchingMembers: membersQuery.isFetching,
isFetchingAvailableRoles: rolesQuery.isLoading || rolesQuery.isFetching,
isRemovingFromOrg: removeFromOrgMutation.isPending,
isAssigningRoles: assignRolesMutation.isPending,
isCreatingInvitation: createInvitationMutation.isPending,
isRevokingInvitation: revokeInvitationMutation.isPending,
isResendingInvitation: resendInvitationMutation.isPending,
isRemovingFromOrg: isMutationLoading(removeFromOrgMutation),
isAssigningRoles: isMutationLoading(assignRolesMutation),
invitationPagination: {
pageSize: invitationPageSize,
currentPage: invitationCurrentPage,
Expand Down
36 changes: 36 additions & 0 deletions packages/react/src/lib/utils/tanstack-compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* TanStack Query v4/v5 compatibility utilities.
* @module tanstack-compat
* @internal
*/

import type { UseMutationResult } from '@tanstack/react-query';
import { keepPreviousData } from '@tanstack/react-query';

/**
* Returns whether a mutation is in a pending/loading state, compatible with both v4 and v5.
* In v5, `isPending` replaces `isLoading` on mutations.
* @param mutation - The mutation result object.
* @returns `true` if the mutation is pending or loading.
*/
export function isMutationLoading<
T extends Pick<UseMutationResult, 'isPending'> & { isLoading?: boolean },
>(mutation: T): boolean {
return mutation.isPending ?? mutation.isLoading ?? false;
}

type PlaceholderDataOption = { placeholderData: typeof keepPreviousData };
type LegacyKeepPreviousOption = { keepPreviousData: true };
type PreviousDataOption = PlaceholderDataOption | LegacyKeepPreviousOption;

/**
* Returns the correct query option for keeping previous data, compatible with both v4 and v5.
* In v5, `keepPreviousData` boolean option was replaced by `placeholderData: keepPreviousData`.
* @returns The appropriate option object to spread into a query config.
*/
export function getPreviousDataOption(): PreviousDataOption {
if (typeof keepPreviousData === 'function') {
return { placeholderData: keepPreviousData };
}
return { keepPreviousData: true };
}