Skip to content

Commit 467f8df

Browse files
committed
refactor: update sorting and group all in a Table
1 parent 497fd63 commit 467f8df

17 files changed

Lines changed: 119 additions & 163 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 = {
@@ -23,7 +24,7 @@ export type PermissionsByRole = {
2324
};
2425

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

2930
if (querySettings.roles) {
@@ -32,14 +33,15 @@ export const getTeamMembers = async (object: string, querySettings: QuerySetting
3233
if (querySettings.search) {
3334
url.searchParams.set('search', querySettings.search);
3435
}
35-
if (querySettings.ordering) {
36-
url.searchParams.set('ordering', querySettings.ordering);
36+
if (querySettings.sortBy && querySettings.order) {
37+
url.searchParams.set('sort_by', querySettings.sortBy);
38+
url.searchParams.set('order', querySettings.order);
3739
}
3840
url.searchParams.set('page_size', querySettings.pageSize.toString());
3941
url.searchParams.set('page', (querySettings.pageIndex + 1).toString());
4042

4143
const { data } = await getAuthenticatedHttpClient().get(url);
42-
return camelCaseObject(data.results);
44+
return camelCaseObject(data);
4345
};
4446

4547
// TODO: this should be replaced in the future with Console API

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

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

11-
const mockMembers = [
12-
{
13-
fullName: 'Alice',
14-
username: 'user1',
15-
16-
roles: ['admin', 'author'],
17-
},
18-
{
19-
fullName: 'Bob',
20-
username: 'user2',
21-
22-
roles: ['collaborator'],
23-
},
24-
];
11+
const mockMembers = {
12+
count: 2,
13+
results: [
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+
],
27+
};
2528

2629
const mockLibrary = {
2730
id: 'lib:123',
@@ -30,6 +33,15 @@ const mockLibrary = {
3033
slug: 'test-library',
3134
};
3235

36+
const mockQuerySettings = {
37+
roles: null,
38+
search: null,
39+
order: null,
40+
sortBy: null,
41+
pageSize: 10,
42+
pageIndex: 0,
43+
};
44+
3345
const createWrapper = () => {
3446
const queryClient = new QueryClient({
3547
defaultOptions: {
@@ -56,17 +68,9 @@ describe('useTeamMembers', () => {
5668

5769
it('returns data when API call succeeds', async () => {
5870
getAuthenticatedHttpClient.mockReturnValue({
59-
get: jest.fn().mockResolvedValue({ data: { results: mockMembers } }),
71+
get: jest.fn().mockResolvedValue({ data: mockMembers }),
6072
});
6173

62-
const mockQuerySettings = {
63-
roles: null,
64-
search: null,
65-
ordering: null,
66-
pageSize: 10,
67-
pageIndex: 0,
68-
};
69-
7074
const { result } = renderHook(() => useTeamMembers('lib:123', mockQuerySettings), {
7175
wrapper: createWrapper(),
7276
});
@@ -82,14 +86,6 @@ describe('useTeamMembers', () => {
8286
get: jest.fn().mockRejectedValue(new Error('API failure')),
8387
});
8488

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

src/authz-module/data/hooks.ts

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
11
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
22
import { appId } from '@src/constants';
3-
import { LibraryMetadata, TeamMember } from '@src/types';
3+
import { LibraryMetadata } from '@src/types';
44
import {
5-
getLibrary, getPermissionsByRole, getTeamMembers, PermissionsByRole, QuerySettings,
5+
getLibrary, getPermissionsByRole, getTeamMembers, GetTeamMembersResponse, PermissionsByRole, QuerySettings,
66
} from './api';
77

88
const authzQueryKeys = {
99
all: [appId, 'authz'] as const,
10-
teamMembers: (object: string, querySettings?: QuerySettings) => [
11-
...authzQueryKeys.all,
12-
'teamMembers',
13-
object,
14-
querySettings?.roles ?? null,
15-
querySettings?.search ?? null,
16-
querySettings?.ordering ?? null,
17-
querySettings?.pageSize ?? 10,
18-
querySettings?.pageIndex ?? 0,
19-
] as const,
10+
teamMembersAll: (scope: string) => [...authzQueryKeys.all, 'teamMembers', scope] as const,
11+
teamMembers: (scope: string, querySettings?: QuerySettings) => [
12+
...authzQueryKeys.teamMembersAll(scope), querySettings] as const,
2013
permissionsByRole: (scope: string) => [...authzQueryKeys.all, 'permissionsByRole', scope] as const,
2114
library: (libraryId: string) => [...authzQueryKeys.all, 'library', libraryId] as const,
2215
};
@@ -25,24 +18,20 @@ const authzQueryKeys = {
2518
* React Query hook to fetch all team members for a specific object/scope.
2619
* It retrieves the full list of members who have access to the given scope.
2720
*
28-
* @param object - The unique identifier of the object/scope
21+
* @param scope - The unique identifier of the object/scope
2922
* @param querySettings - Optional query parameters for filtering, sorting, and pagination
3023
*
3124
* @example
3225
* ```tsx
3326
* const { data: teamMembers, isLoading, isError } = useTeamMembers('lib:123', querySettings);
3427
* ```
3528
*/
36-
export const useTeamMembers = (object: string, querySettings: QuerySettings) => {
37-
const queryKey = authzQueryKeys.teamMembers(object, querySettings);
38-
39-
return useQuery<TeamMember[], Error>({
40-
queryKey,
41-
queryFn: () => getTeamMembers(object, querySettings),
42-
staleTime: 1000 * 60 * 30, // refetch after 30 minutes
43-
refetchOnWindowFocus: false,
44-
});
45-
};
29+
export const useTeamMembers = (scope: string, querySettings: QuerySettings) => useQuery<GetTeamMembersResponse, Error>({
30+
queryKey: authzQueryKeys.teamMembers(scope, querySettings),
31+
queryFn: () => getTeamMembers(scope, querySettings),
32+
staleTime: 1000 * 60 * 30, // refetch after 30 minutes
33+
refetchOnWindowFocus: false,
34+
});
4635

4736
/**
4837
* 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)