diff --git a/src/frontend/apps/desk/next-env.d.ts b/src/frontend/apps/desk/next-env.d.ts index 62b8a52d3..95ddcaed0 100644 --- a/src/frontend/apps/desk/next-env.d.ts +++ b/src/frontend/apps/desk/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. diff --git a/src/frontend/apps/desk/src/features/teams/team-management/api/useTeams.tsx b/src/frontend/apps/desk/src/features/teams/team-management/api/useTeams.tsx index f259f2634..ac7784096 100644 --- a/src/frontend/apps/desk/src/features/teams/team-management/api/useTeams.tsx +++ b/src/frontend/apps/desk/src/features/teams/team-management/api/useTeams.tsx @@ -1,11 +1,6 @@ -import { - DefinedInitialDataInfiniteOptions, - InfiniteData, - QueryKey, - useInfiniteQuery, -} from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; -import { APIError, APIList, errorCauses, fetchAPI } from '@/api'; +import { APIError, errorCauses, fetchAPI } from '@/api'; import { Team } from '../types'; @@ -17,18 +12,14 @@ export enum TeamsOrdering { export type TeamsParams = { ordering: TeamsOrdering; }; -type TeamsAPIParams = TeamsParams & { - page: number; -}; -type TeamsResponse = APIList; +type TeamsResponse = Team[]; export const getTeams = async ({ ordering, - page, -}: TeamsAPIParams): Promise => { - const orderingQuery = ordering ? `&ordering=${ordering}` : ''; - const response = await fetchAPI(`teams/?page=${page}${orderingQuery}`); +}: TeamsParams): Promise => { + const orderingQuery = ordering ? `?ordering=${ordering}` : ''; + const response = await fetchAPI(`teams/${orderingQuery}`); if (!response.ok) { throw new APIError('Failed to get the teams', await errorCauses(response)); @@ -39,33 +30,9 @@ export const getTeams = async ({ export const KEY_LIST_TEAM = 'teams'; -export function useTeams( - param: TeamsParams, - queryConfig?: DefinedInitialDataInfiniteOptions< - TeamsResponse, - APIError, - InfiniteData, - QueryKey, - number - >, -) { - return useInfiniteQuery< - TeamsResponse, - APIError, - InfiniteData, - QueryKey, - number - >({ - initialPageParam: 1, - queryKey: [KEY_LIST_TEAM, param], - queryFn: ({ pageParam }) => - getTeams({ - ...param, - page: pageParam, - }), - getNextPageParam(lastPage, allPages) { - return lastPage.next ? allPages.length + 1 : undefined; - }, - ...queryConfig, +export function useTeams(params: TeamsParams) { + return useQuery({ + queryKey: [KEY_LIST_TEAM, params], + queryFn: () => getTeams(params), }); } diff --git a/src/frontend/apps/desk/src/features/teams/teams-panel/__tests__/PanelTeams.test.tsx b/src/frontend/apps/desk/src/features/teams/teams-panel/__tests__/PanelTeams.test.tsx index b8ec69ab4..68d355c37 100644 --- a/src/frontend/apps/desk/src/features/teams/teams-panel/__tests__/PanelTeams.test.tsx +++ b/src/frontend/apps/desk/src/features/teams/teams-panel/__tests__/PanelTeams.test.tsx @@ -23,10 +23,7 @@ describe('PanelTeams', () => { }); it('renders with no team to display', async () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { - count: 0, - results: [], - }); + fetchMock.mock(`end:/teams/?ordering=-created_at`, []); render(, { wrapper: AppWrapper }); @@ -40,16 +37,13 @@ describe('PanelTeams', () => { }); it('renders an empty team', async () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { - count: 1, - results: [ - { - id: '1', - name: 'Team 1', - accesses: [], - }, - ], - }); + fetchMock.mock(`end:/teams/?ordering=-created_at`, [ + { + id: '1', + name: 'Team 1', + accesses: [], + }, + ]); render(, { wrapper: AppWrapper }); @@ -59,21 +53,18 @@ describe('PanelTeams', () => { }); it('renders a team with only 1 member', async () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { - count: 1, - results: [ - { - id: '1', - name: 'Team 1', - accesses: [ - { - id: '1', - role: 'owner', - }, - ], - }, - ], - }); + fetchMock.mock(`end:/teams/?ordering=-created_at`, [ + { + id: '1', + name: 'Team 1', + accesses: [ + { + id: '1', + role: 'owner', + }, + ], + }, + ]); render(, { wrapper: AppWrapper }); @@ -83,25 +74,22 @@ describe('PanelTeams', () => { }); it('renders a non-empty team', () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { - count: 1, - results: [ - { - id: '1', - name: 'Team 1', - accesses: [ - { - id: '1', - role: 'admin', - }, - { - id: '2', - role: 'member', - }, - ], - }, - ], - }); + fetchMock.mock(`end:/teams/?ordering=-created_at`, [ + { + id: '1', + name: 'Team 1', + accesses: [ + { + id: '1', + role: 'admin', + }, + { + id: '2', + role: 'member', + }, + ], + }, + ]); render(, { wrapper: AppWrapper }); @@ -109,7 +97,7 @@ describe('PanelTeams', () => { }); it('renders the error', async () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/teams/?ordering=-created_at`, { status: 500, }); @@ -125,10 +113,7 @@ describe('PanelTeams', () => { }); it('renders with team panel open', async () => { - fetchMock.mock(`end:/teams/?page=1&ordering=-created_at`, { - count: 1, - results: [], - }); + fetchMock.mock(`end:/teams/?ordering=-created_at`, []); render(, { wrapper: AppWrapper }); @@ -140,10 +125,7 @@ describe('PanelTeams', () => { }); it('closes and opens the team panel', async () => { - fetchMock.get(`end:/teams/?page=1&ordering=-created_at`, { - count: 1, - results: [], - }); + fetchMock.get(`end:/teams/?ordering=-created_at`, []); render(, { wrapper: AppWrapper }); diff --git a/src/frontend/apps/desk/src/features/teams/teams-panel/components/TeamList.tsx b/src/frontend/apps/desk/src/features/teams/teams-panel/components/TeamList.tsx index ac1002b61..6331cc96a 100644 --- a/src/frontend/apps/desk/src/features/teams/teams-panel/components/TeamList.tsx +++ b/src/frontend/apps/desk/src/features/teams/teams-panel/components/TeamList.tsx @@ -1,9 +1,8 @@ import { Loader } from '@openfun/cunningham-react'; -import React, { useMemo, useRef } from 'react'; +import React, { useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, Text } from '@/components'; -import { InfiniteScroll } from '@/components/InfiniteScroll'; import { Team, useTeams } from '@/features/teams/team-management'; import { useTeamStore } from '../store'; @@ -57,39 +56,14 @@ const TeamListState = ({ isLoading, isError, teams }: PanelTeamsStateProps) => { export const TeamList = () => { const ordering = useTeamStore((state) => state.ordering); - const { - data, - isError, - isLoading, - fetchNextPage, - hasNextPage, - isFetchingNextPage, - } = useTeams({ + const { data, isError, isLoading } = useTeams({ ordering, }); const containerRef = useRef(null); - const teams = useMemo(() => { - return data?.pages.reduce((acc, page) => { - return acc.concat(page.results); - }, [] as Team[]); - }, [data?.pages]); return ( - { - void fetchNextPage(); - }} - scrollContainer={containerRef.current} - as="ul" - $margin={{ top: 'none' }} - $padding="none" - role="listbox" - > - - + ); }; diff --git a/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts index 48eae6cee..594bf1002 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/keyboard-navigation.spec.ts @@ -26,9 +26,9 @@ const payloadGetTeams = { }; const mockApiRequests = (page: Page) => { - void page.route('**/teams/?page=1&ordering=-created_at', (route) => { + void page.route('**/teams/?ordering=-created_at', (route) => { void route.fulfill({ - json: payloadGetTeams, + json: payloadGetTeams.results, }); }); }; diff --git a/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts b/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts index d06b12953..02749701d 100644 --- a/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-desk/teams-panel.spec.ts @@ -1,7 +1,5 @@ import { expect, test } from '@playwright/test'; -import { waitForElementCount } from '../helpers'; - import { createTeam, keyCloakSignIn } from './common'; test.beforeEach(async ({ page, browserName }) => { @@ -31,13 +29,13 @@ test.describe('Teams Panel', () => { test('checks the sort button', async ({ page }) => { const responsePromiseSortDesc = page.waitForResponse( (response) => - response.url().includes('/teams/?page=1&ordering=-created_at') && + response.url().includes('/teams/?ordering=-created_at') && response.status() === 200, ); const responsePromiseSortAsc = page.waitForResponse( (response) => - response.url().includes('/teams/?page=1&ordering=created_at') && + response.url().includes('/teams/?ordering=created_at') && response.status() === 200, ); @@ -62,24 +60,6 @@ test.describe('Teams Panel', () => { expect(responseSortDesc.ok()).toBeTruthy(); }); - test('checks the infinite scroll', async ({ page, browserName }) => { - test.setTimeout(90000); - const panel = page.getByLabel('Teams panel').first(); - - const randomTeams = await createTeam( - page, - 'team-infinite', - browserName, - 40, - ); - - await expect(panel.locator('li')).toHaveCount(20); - await panel.getByText(randomTeams[24]).click(); - - await waitForElementCount(panel.locator('li'), 21, 10000); - expect(await panel.locator('li').count()).toBeGreaterThan(20); - }); - test('checks the hover and selected state', async ({ page, browserName }) => { const panel = page.getByLabel('Teams panel').first(); await createTeam(page, 'team-hover', browserName, 2); diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index e11c321c6..1199f0035 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -3492,7 +3492,7 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== -"@types/node@*": +"@types/node@*", "@types/node@20.16.10": version "20.16.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.10.tgz#0cc3fdd3daf114a4776f54ba19726a01c907ef71" integrity sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA== @@ -3509,7 +3509,7 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== -"@types/react-dom@*": +"@types/react-dom@*", "@types/react-dom@18.3.0": version "18.3.0" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== @@ -8485,7 +8485,7 @@ safe-regex-test@^1.0.3: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@^1.80.3: +sass@1.80.3: version "1.80.3" resolved "https://registry.yarnpkg.com/sass/-/sass-1.80.3.tgz#3f63dd527647d2b3de35f36acb971bda80517423" integrity sha512-ptDWyVmDMVielpz/oWy3YP3nfs7LpJTHIJZboMVs8GEC9eUmtZTZhMHlTW98wY4aEorDfjN38+Wr/XjskFWcfA== @@ -9259,7 +9259,7 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" -typescript@*, typescript@^5.0.4: +typescript@*, typescript@5.6.2, typescript@^5.0.4: version "5.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==