Skip to content

Commit c238129

Browse files
committed
refactor: update sorting and group all in a Table
1 parent 38d2b54 commit c238129

17 files changed

Lines changed: 120 additions & 165 deletions

src/authz-module/data/api.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import { getApiUrl, getStudioApiUrl } from '@src/data/utils';
66
export interface QuerySettings {
77
roles: string | null;
88
search: string | null;
9-
ordering: string | null;
9+
order: string | null;
10+
sortBy: string | null;
1011
pageSize: number;
1112
pageIndex: number;
1213
}
1314

1415
export interface GetTeamMembersResponse {
15-
members: TeamMember[];
16-
totalCount: number;
16+
results: TeamMember[];
17+
count: number;
1718
}
1819

1920
export type PermissionsByRole = {
@@ -33,7 +34,7 @@ export interface AssignTeamMembersRoleRequest {
3334
}
3435

3536
// TODO: replece api path once is created
36-
export const getTeamMembers = async (object: string, querySettings: QuerySettings): Promise<TeamMember[]> => {
37+
export const getTeamMembers = async (object: string, querySettings: QuerySettings): Promise<GetTeamMembersResponse> => {
3738
const url = new URL(getApiUrl(`/api/authz/v1/roles/users/?scope=${object}`));
3839

3940
if (querySettings.roles) {
@@ -42,14 +43,15 @@ export const getTeamMembers = async (object: string, querySettings: QuerySetting
4243
if (querySettings.search) {
4344
url.searchParams.set('search', querySettings.search);
4445
}
45-
if (querySettings.ordering) {
46-
url.searchParams.set('ordering', querySettings.ordering);
46+
if (querySettings.sortBy && querySettings.order) {
47+
url.searchParams.set('sort_by', querySettings.sortBy);
48+
url.searchParams.set('order', querySettings.order);
4749
}
4850
url.searchParams.set('page_size', querySettings.pageSize.toString());
4951
url.searchParams.set('page', (querySettings.pageIndex + 1).toString());
5052

5153
const { data } = await getAuthenticatedHttpClient().get(url);
52-
return camelCaseObject(data.results);
54+
return camelCaseObject(data);
5355
};
5456

5557
export const assignTeamMembersRole = async (

src/authz-module/data/hooks.test.tsx

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,23 @@ jest.mock('@edx/frontend-platform/auth', () => ({
1010
getAuthenticatedHttpClient: jest.fn(),
1111
}));
1212

13-
const mockMembers = [
14-
{
15-
fullName: 'Alice',
16-
username: 'user1',
17-
18-
roles: ['admin', 'author'],
19-
},
20-
{
21-
fullName: 'Bob',
22-
username: 'user2',
23-
24-
roles: ['collaborator'],
25-
},
26-
];
13+
const mockMembers = {
14+
count: 2,
15+
results: [
16+
{
17+
fullName: 'Alice',
18+
username: 'user1',
19+
20+
roles: ['admin', 'author'],
21+
},
22+
{
23+
fullName: 'Bob',
24+
username: 'user2',
25+
26+
roles: ['collaborator'],
27+
},
28+
],
29+
};
2730

2831
const mockLibrary = {
2932
id: 'lib:123',
@@ -32,6 +35,15 @@ const mockLibrary = {
3235
slug: 'test-library',
3336
};
3437

38+
const mockQuerySettings = {
39+
roles: null,
40+
search: null,
41+
order: null,
42+
sortBy: null,
43+
pageSize: 10,
44+
pageIndex: 0,
45+
};
46+
3547
const createWrapper = () => {
3648
const queryClient = new QueryClient({
3749
defaultOptions: {
@@ -58,17 +70,9 @@ describe('useTeamMembers', () => {
5870

5971
it('returns data when API call succeeds', async () => {
6072
getAuthenticatedHttpClient.mockReturnValue({
61-
get: jest.fn().mockResolvedValue({ data: { results: mockMembers } }),
73+
get: jest.fn().mockResolvedValue({ data: mockMembers }),
6274
});
6375

64-
const mockQuerySettings = {
65-
roles: null,
66-
search: null,
67-
ordering: null,
68-
pageSize: 10,
69-
pageIndex: 0,
70-
};
71-
7276
const { result } = renderHook(() => useTeamMembers('lib:123', mockQuerySettings), {
7377
wrapper: createWrapper(),
7478
});
@@ -84,14 +88,6 @@ describe('useTeamMembers', () => {
8488
get: jest.fn().mockRejectedValue(new Error('API failure')),
8589
});
8690

87-
const mockQuerySettings = {
88-
roles: null,
89-
search: null,
90-
ordering: null,
91-
pageSize: 10,
92-
pageIndex: 0,
93-
};
94-
9591
const { result } = renderHook(() => useTeamMembers('lib:123', mockQuerySettings), {
9692
wrapper: createWrapper(),
9793
});

src/authz-module/data/hooks.ts

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,17 @@ import {
22
useMutation, useQuery, useQueryClient, useSuspenseQuery,
33
} from '@tanstack/react-query';
44
import { appId } from '@src/constants';
5-
import { LibraryMetadata, TeamMember } from '@src/types';
5+
import { LibraryMetadata } from '@src/types';
66
import {
7-
assignTeamMembersRole,
8-
AssignTeamMembersRoleRequest,
9-
getLibrary, getPermissionsByRole, getTeamMembers, PermissionsByRole, QuerySettings,
7+
assignTeamMembersRole, AssignTeamMembersRoleRequest, getLibrary, getPermissionsByRole, getTeamMembers,
8+
GetTeamMembersResponse, PermissionsByRole, QuerySettings,
109
} from './api';
1110

1211
const authzQueryKeys = {
1312
all: [appId, 'authz'] as const,
14-
teamMembers: (object: string, querySettings?: QuerySettings) => [
15-
...authzQueryKeys.all,
16-
'teamMembers',
17-
object,
18-
querySettings?.roles ?? null,
19-
querySettings?.search ?? null,
20-
querySettings?.ordering ?? null,
21-
querySettings?.pageSize ?? 10,
22-
querySettings?.pageIndex ?? 0,
23-
] as const,
13+
teamMembersAll: (scope: string) => [...authzQueryKeys.all, 'teamMembers', scope] as const,
14+
teamMembers: (scope: string, querySettings?: QuerySettings) => [
15+
...authzQueryKeys.teamMembersAll(scope), querySettings] as const,
2416
permissionsByRole: (scope: string) => [...authzQueryKeys.all, 'permissionsByRole', scope] as const,
2517
library: (libraryId: string) => [...authzQueryKeys.all, 'library', libraryId] as const,
2618
};
@@ -29,24 +21,20 @@ const authzQueryKeys = {
2921
* React Query hook to fetch all team members for a specific object/scope.
3022
* It retrieves the full list of members who have access to the given scope.
3123
*
32-
* @param object - The unique identifier of the object/scope
24+
* @param scope - The unique identifier of the object/scope
3325
* @param querySettings - Optional query parameters for filtering, sorting, and pagination
3426
*
3527
* @example
3628
* ```tsx
3729
* const { data: teamMembers, isLoading, isError } = useTeamMembers('lib:123', querySettings);
3830
* ```
3931
*/
40-
export const useTeamMembers = (object: string, querySettings: QuerySettings) => {
41-
const queryKey = authzQueryKeys.teamMembers(object, querySettings);
42-
43-
return useQuery<TeamMember[], Error>({
44-
queryKey,
45-
queryFn: () => getTeamMembers(object, querySettings),
46-
staleTime: 1000 * 60 * 30, // refetch after 30 minutes
47-
refetchOnWindowFocus: false,
48-
});
49-
};
32+
export const useTeamMembers = (scope: string, querySettings: QuerySettings) => useQuery<GetTeamMembersResponse, Error>({
33+
queryKey: authzQueryKeys.teamMembers(scope, querySettings),
34+
queryFn: () => getTeamMembers(scope, querySettings),
35+
staleTime: 1000 * 60 * 30, // refetch after 30 minutes
36+
refetchOnWindowFocus: false,
37+
});
5038

5139
/**
5240
* React Query hook to fetch all the roles for the specific object/scope.

src/authz-module/libraries-manager/components/MultipleChoiceFilter.test.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/MultipleChoiceFilter.test.tsx

File renamed without changes.

src/authz-module/libraries-manager/components/MultipleChoiceFilter.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/MultipleChoiceFilter.tsx

File renamed without changes.

src/authz-module/libraries-manager/components/SearchFilter.test.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/SearchFilter.test.tsx

File renamed without changes.

src/authz-module/libraries-manager/components/SearchFilter.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/SearchFilter.tsx

File renamed without changes.

src/authz-module/libraries-manager/components/SortDropdown.test.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/SortDropdown.test.tsx

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ describe('SortDropdown', () => {
5656

5757
expect(screen.getByText('Name A-Z')).toBeInTheDocument();
5858
expect(screen.getByText('Name Z-A')).toBeInTheDocument();
59-
expect(screen.getByText('Newest')).toBeInTheDocument();
60-
expect(screen.getByText('Oldest')).toBeInTheDocument();
6159
});
6260

6361
it('should display current sort when a sort is active', () => {
@@ -86,32 +84,6 @@ describe('SortDropdown', () => {
8684
expect(screen.getByText('Name Z-A')).toBeInTheDocument();
8785
});
8886

89-
it('should display newest sort correctly', () => {
90-
const contextWithSort = {
91-
state: {
92-
...defaultDataTableState,
93-
sortBy: [{ id: 'createdAt', desc: true }],
94-
},
95-
};
96-
97-
renderSortDropdown(contextWithSort);
98-
99-
expect(screen.getByText('Newest')).toBeInTheDocument();
100-
});
101-
102-
it('should display oldest sort correctly', () => {
103-
const contextWithSort = {
104-
state: {
105-
...defaultDataTableState,
106-
sortBy: [{ id: 'createdAt', desc: false }],
107-
},
108-
};
109-
110-
renderSortDropdown(contextWithSort);
111-
112-
expect(screen.getByText('Oldest')).toBeInTheDocument();
113-
});
114-
11587
it('should handle sort selection and call toggleSortBy', () => {
11688
renderSortDropdown();
11789

@@ -133,14 +105,6 @@ describe('SortDropdown', () => {
133105
});
134106

135107
expect(mockToggleSortBy).toHaveBeenCalledWith('username', true);
136-
137-
const newestOption = screen.getByText('Newest');
138-
139-
act(() => {
140-
fireEvent.click(newestOption);
141-
});
142-
143-
expect(mockToggleSortBy).toHaveBeenCalledWith('createdAt', true);
144108
});
145109

146110
it('should mark the active sort option as active', () => {

src/authz-module/libraries-manager/components/SortDropdown.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/SortDropdown.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ interface SortByOptions {
2525
const SORT_BY_OPTIONS: SortByOptions = {
2626
'name-a-z': { id: 'username', desc: false },
2727
'name-z-a': { id: 'username', desc: true },
28-
newest: { id: 'createdAt', desc: true },
29-
oldest: { id: 'createdAt', desc: false },
3028
};
3129

3230
const SortDropdown: FC = () => {
@@ -37,8 +35,6 @@ const SortDropdown: FC = () => {
3735
const SORT_LABELS: Record<string, string> = useMemo(() => ({
3836
'name-a-z': intl.formatMessage({ id: 'authz.libraries.team.table.sort.name-a-z', defaultMessage: 'Name A-Z' }),
3937
'name-z-a': intl.formatMessage({ id: 'authz.libraries.team.table.sort.name-z-a', defaultMessage: 'Name Z-A' }),
40-
newest: intl.formatMessage({ id: 'authz.libraries.team.table.sort.newest', defaultMessage: 'Newest' }),
41-
oldest: intl.formatMessage({ id: 'authz.libraries.team.table.sort.oldest', defaultMessage: 'Oldest' }),
4238
// eslint-disable-next-line react-hooks/exhaustive-deps
4339
}), []);
4440

src/authz-module/libraries-manager/components/TableControlBar.test.tsx renamed to src/authz-module/libraries-manager/components/TeamTable/components/TableControlBar.test.tsx

File renamed without changes.

0 commit comments

Comments
 (0)