Skip to content

Commit 4648334

Browse files
committed
EES-4996 Add pagination to API data set version history
1 parent cd058d1 commit 4648334

File tree

8 files changed

+385
-118
lines changed

8 files changed

+385
-118
lines changed

src/explore-education-statistics-common/src/components/Pagination.tsx

+12-16
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,13 @@ import { ArrowLeft, ArrowRight } from '@common/components/ArrowIcons';
22
import generatePageNumbers from '@common/components/util/generatePageNumbers';
33
import { useMobileMedia } from '@common/hooks/useMedia';
44
import appendQuery from '@common/utils/url/appendQuery';
5-
import { PublicationSortOption } from '@common/services/publicationService';
65
import classNames from 'classnames';
7-
import React, { ReactNode } from 'react';
6+
import { ParsedUrlQueryInput } from 'querystring';
7+
import React, { MouseEvent, ReactNode } from 'react';
88
import VisuallyHidden from './VisuallyHidden';
99

1010
const paginationLinkClassName = 'govuk-pagination__link';
1111

12-
type Params = {
13-
newDesign?: boolean;
14-
page?: number;
15-
sortBy?: PublicationSortOption;
16-
};
17-
1812
interface LinkRenderProps {
1913
'aria-current'?: 'page';
2014
'aria-label'?: string;
@@ -23,14 +17,15 @@ interface LinkRenderProps {
2317
className: string;
2418
rel?: 'next' | 'prev';
2519
to: string;
26-
onClick?: () => void;
20+
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
2721
}
2822

2923
export interface PaginationProps {
3024
baseUrl?: string;
3125
currentPage: number;
3226
label?: string;
33-
queryParams?: Params;
27+
queryParams?: ParsedUrlQueryInput;
28+
pageParam?: string;
3429
renderLink: (props: LinkRenderProps) => ReactNode;
3530
totalPages: number;
3631
onClick?: (pageNumber: number) => void;
@@ -40,6 +35,7 @@ const Pagination = ({
4035
baseUrl = '',
4136
currentPage,
4237
label = 'Pagination',
38+
pageParam = 'page',
4339
queryParams,
4440
renderLink,
4541
totalPages,
@@ -65,9 +61,9 @@ const Pagination = ({
6561
className: paginationLinkClassName,
6662
rel: 'prev',
6763
'data-testid': 'pagination-previous',
68-
to: appendQuery<Params>(baseUrl, {
64+
to: appendQuery(baseUrl, {
6965
...queryParams,
70-
page: currentPage - 1,
66+
[pageParam]: currentPage - 1,
7167
}),
7268
children: (
7369
<>
@@ -108,9 +104,9 @@ const Pagination = ({
108104
'aria-current': currentPage === pageNumber ? 'page' : undefined,
109105
'aria-label': `Page ${pageNumber}`,
110106
className: paginationLinkClassName,
111-
to: appendQuery<Params>(baseUrl, {
107+
to: appendQuery(baseUrl, {
112108
...queryParams,
113-
page: pageNumber,
109+
[pageParam]: pageNumber,
114110
}),
115111
children: <>{pageNumber}</>,
116112
onClick: () => onClick?.(pageNumber),
@@ -126,9 +122,9 @@ const Pagination = ({
126122
className: paginationLinkClassName,
127123
rel: 'next',
128124
'data-testid': 'pagination-next',
129-
to: appendQuery<Params>(baseUrl, {
125+
to: appendQuery(baseUrl, {
130126
...queryParams,
131-
page: currentPage + 1,
127+
[pageParam]: currentPage + 1,
132128
}),
133129
children: (
134130
<>

src/explore-education-statistics-common/src/components/__tests__/Pagination.test.tsx

+77-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Pagination from '@common/components/Pagination';
1+
import Pagination, { PaginationProps } from '@common/components/Pagination';
22
import { render as baseRender, screen } from '@testing-library/react';
33
import React from 'react';
44

@@ -12,6 +12,76 @@ jest.mock('@common/hooks/useMedia', () => ({
1212
}));
1313

1414
describe('Pagination', () => {
15+
test('renders correct links with custom `pageParam` prop', () => {
16+
render({
17+
currentPage: 1,
18+
totalPages: 2,
19+
pageParam: 'customPage',
20+
});
21+
22+
const links = screen.getAllByRole('link');
23+
expect(links).toHaveLength(3);
24+
25+
expect(links[0]).toHaveAttribute('href', '/test-url?customPage=1');
26+
expect(links[1]).toHaveAttribute('href', '/test-url?customPage=2');
27+
expect(links[2]).toHaveAttribute('href', '/test-url?customPage=2');
28+
});
29+
30+
test('renders correct links with custom `queryParams` prop', () => {
31+
render({
32+
currentPage: 1,
33+
totalPages: 2,
34+
queryParams: {
35+
foo: 'bar',
36+
baz: 'qux',
37+
},
38+
});
39+
40+
const links = screen.getAllByRole('link');
41+
expect(links).toHaveLength(3);
42+
43+
expect(links[0]).toHaveAttribute(
44+
'href',
45+
'/test-url?foo=bar&baz=qux&page=1',
46+
);
47+
expect(links[1]).toHaveAttribute(
48+
'href',
49+
'/test-url?foo=bar&baz=qux&page=2',
50+
);
51+
expect(links[2]).toHaveAttribute(
52+
'href',
53+
'/test-url?foo=bar&baz=qux&page=2',
54+
);
55+
});
56+
57+
test('renders links with custom `pageParam` and `queryParams` props', () => {
58+
render({
59+
currentPage: 1,
60+
totalPages: 2,
61+
pageParam: 'customPage',
62+
queryParams: {
63+
foo: 'bar',
64+
baz: 'qux',
65+
},
66+
});
67+
68+
const links = screen.getAllByRole('link');
69+
expect(links).toHaveLength(3);
70+
71+
expect(links[0]).toHaveAttribute(
72+
'href',
73+
'/test-url?foo=bar&baz=qux&customPage=1',
74+
);
75+
expect(links[1]).toHaveAttribute(
76+
'href',
77+
'/test-url?foo=bar&baz=qux&customPage=2',
78+
);
79+
expect(links[2]).toHaveAttribute(
80+
'href',
81+
'/test-url?foo=bar&baz=qux&customPage=2',
82+
);
83+
});
84+
1585
describe('desktop', () => {
1686
test('renders the pagination without spacers when there are fewer than 8 pages', () => {
1787
render({ currentPage: 3, totalPages: 5 });
@@ -482,19 +552,15 @@ describe('Pagination', () => {
482552
});
483553

484554
function render({
485-
currentPage,
486-
totalPages,
487-
}: {
488-
currentPage: number;
489-
totalPages: number;
490-
}) {
555+
baseUrl = '/test-url',
556+
...props
557+
}: Omit<PaginationProps, 'renderLink'>) {
491558
baseRender(
492559
<Pagination
493-
baseUrl="/test-url"
494-
currentPage={currentPage}
560+
{...props}
561+
baseUrl={baseUrl}
495562
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-props-no-spreading
496-
renderLink={props => <a {...props} href={props.to} />}
497-
totalPages={totalPages}
563+
renderLink={linkProps => <a {...linkProps} href={linkProps.to} />}
498564
/>,
499565
);
500566
}

src/explore-education-statistics-frontend/src/components/Pagination.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ const Pagination = ({
1717
...props
1818
}: Props) => {
1919
const router = useRouter();
20+
2021
return (
2122
<BasePagination
2223
{...props}
23-
baseUrl={baseUrl ?? router.pathname}
24+
baseUrl={baseUrl}
2425
queryParams={queryParams ?? router.query}
2526
renderLink={({ 'data-testid': testId, ...linkProps }) => (
2627
<Link

src/explore-education-statistics-frontend/src/modules/data-catalogue/DataSetFilePage.tsx

+40-31
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import useToggle from '@common/hooks/useToggle';
88
import downloadService from '@common/services/downloadService';
99
import { PaginatedList } from '@common/services/types/pagination';
1010
import { Dictionary } from '@common/types';
11+
import appendQuery from '@common/utils/url/appendQuery';
1112
import Page from '@frontend/components/Page';
1213
import withAxiosHandler from '@frontend/middleware/ssr/withAxiosHandler';
1314
import DataSetFileApiQuickStart from '@frontend/modules/data-catalogue/components/DataSetFileApiQuickStart';
@@ -29,6 +30,7 @@ import { logEvent } from '@frontend/services/googleAnalyticsService';
2930
import { dehydrate, QueryClient } from '@tanstack/react-query';
3031
import classNames from 'classnames';
3132
import { GetServerSideProps } from 'next';
33+
import { useRouter } from 'next/router';
3234
import React, { useEffect, useState } from 'react';
3335

3436
// TODO EES-4856
@@ -66,14 +68,12 @@ export type PageSectionId = keyof PageSection;
6668
interface Props {
6769
apiDataSet?: ApiDataSet;
6870
apiDataSetVersion?: ApiDataSetVersion;
69-
apiDataSetVersions?: PaginatedList<ApiDataSetVersion>;
7071
dataSetFile: DataSetFile;
7172
}
7273

7374
export default function DataSetFilePage({
7475
apiDataSet,
7576
apiDataSetVersion,
76-
apiDataSetVersions,
7777
dataSetFile,
7878
}: Props) {
7979
const [activeSection, setActiveSection] =
@@ -115,7 +115,16 @@ export default function DataSetFilePage({
115115
pageSections[pageSectionId]
116116
) {
117117
setActiveSection(pageSectionId);
118-
window.history.pushState({}, '', `#${pageSectionId}`);
118+
119+
const queryString = (
120+
window.location.search || window.location.hash
121+
).split('?')[1];
122+
123+
const url = queryString
124+
? `#${pageSectionId}?${queryString}`
125+
: `#${pageSectionId}`;
126+
127+
window.history.pushState({}, '', url);
119128
}
120129
});
121130
}, 10);
@@ -219,19 +228,19 @@ export default function DataSetFilePage({
219228
onClickDownload={handleDownload}
220229
/>
221230

222-
{apiDataSetVersions && apiDataSetVersion && (
223-
<DataSetFileApiVersionHistory
224-
currentVersion={apiDataSetVersion.version}
225-
dataSetFileId={dataSetFile.id}
226-
dataSetVersions={apiDataSetVersions}
227-
/>
228-
)}
229231
{apiDataSet && apiDataSetVersion && (
230-
<DataSetFileApiQuickStart
231-
id={apiDataSet.id}
232-
name={apiDataSet.title}
233-
version={apiDataSetVersion.version}
234-
/>
232+
<>
233+
<DataSetFileApiVersionHistory
234+
apiDataSetId={apiDataSet?.id}
235+
currentVersion={apiDataSetVersion.version}
236+
/>
237+
238+
<DataSetFileApiQuickStart
239+
id={apiDataSet.id}
240+
name={apiDataSet.title}
241+
version={apiDataSetVersion.version}
242+
/>
243+
</>
235244
)}
236245
</div>
237246
</div>
@@ -243,7 +252,7 @@ export default function DataSetFilePage({
243252

244253
export const getServerSideProps: GetServerSideProps<Props> = withAxiosHandler(
245254
async context => {
246-
const { dataSetFileId } = context.query as Dictionary<string>;
255+
const { dataSetFileId, versionPage } = context.query as Dictionary<string>;
247256

248257
const queryClient = new QueryClient();
249258

@@ -256,25 +265,25 @@ export const getServerSideProps: GetServerSideProps<Props> = withAxiosHandler(
256265
};
257266

258267
if (dataSetFile.api) {
259-
const [apiDataSet, apiDataSetVersion, apiDataSetVersions] =
260-
await Promise.all([
261-
await queryClient.fetchQuery(
262-
apiDataSetQueries.getDataSet(dataSetFile.api.id),
263-
),
264-
await queryClient.fetchQuery(
265-
apiDataSetQueries.getDataSetVersion(
266-
dataSetFile.api.id,
267-
dataSetFile.api.version,
268-
),
269-
),
270-
await queryClient.fetchQuery(
271-
apiDataSetQueries.listDataSetVersions(dataSetFile.api.id),
268+
const [apiDataSet, apiDataSetVersion] = await Promise.all([
269+
await queryClient.fetchQuery(
270+
apiDataSetQueries.getDataSet(dataSetFile.api.id),
271+
),
272+
await queryClient.fetchQuery(
273+
apiDataSetQueries.getDataSetVersion(
274+
dataSetFile.api.id,
275+
dataSetFile.api.version,
272276
),
273-
]);
277+
),
278+
await queryClient.fetchQuery(
279+
apiDataSetQueries.listDataSetVersions(dataSetFile.api.id, {
280+
page: versionPage ? Number(versionPage) : 1,
281+
}),
282+
),
283+
]);
274284

275285
props.apiDataSet = apiDataSet;
276286
props.apiDataSetVersion = apiDataSetVersion;
277-
props.apiDataSetVersions = apiDataSetVersions;
278287
}
279288

280289
return {

src/explore-education-statistics-frontend/src/modules/data-catalogue/__tests__/DataSetFilePage.test.tsx

-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import DataSetFilePage from '@frontend/modules/data-catalogue/DataSetFilePage';
44
import {
55
testApiDataSet,
66
testApiDataSetVersion,
7-
testApiDataSetVersions,
87
testDataSetFile,
98
} from '@frontend/modules/data-catalogue/__data__/testDataSets';
109
import { screen, waitFor, within } from '@testing-library/react';
@@ -152,7 +151,6 @@ describe('DataSetFilePage', () => {
152151
<DataSetFilePage
153152
apiDataSet={testApiDataSet}
154153
apiDataSetVersion={testApiDataSetVersion}
155-
apiDataSetVersions={testApiDataSetVersions}
156154
dataSetFile={testDataSetFile}
157155
/>,
158156
);
@@ -169,7 +167,6 @@ describe('DataSetFilePage', () => {
169167
<DataSetFilePage
170168
apiDataSet={testApiDataSet}
171169
apiDataSetVersion={testApiDataSetVersion}
172-
apiDataSetVersions={testApiDataSetVersions}
173170
dataSetFile={testDataSetFile}
174171
/>,
175172
);
@@ -193,7 +190,6 @@ describe('DataSetFilePage', () => {
193190
<DataSetFilePage
194191
apiDataSet={testApiDataSet}
195192
apiDataSetVersion={testApiDataSetVersion}
196-
apiDataSetVersions={testApiDataSetVersions}
197193
dataSetFile={testDataSetFile}
198194
/>,
199195
);
@@ -210,7 +206,6 @@ describe('DataSetFilePage', () => {
210206
<DataSetFilePage
211207
apiDataSet={testApiDataSet}
212208
apiDataSetVersion={testApiDataSetVersion}
213-
apiDataSetVersions={testApiDataSetVersions}
214209
dataSetFile={testDataSetFile}
215210
/>,
216211
);
@@ -227,7 +222,6 @@ describe('DataSetFilePage', () => {
227222
<DataSetFilePage
228223
apiDataSet={testApiDataSet}
229224
apiDataSetVersion={testApiDataSetVersion}
230-
apiDataSetVersions={testApiDataSetVersions}
231225
dataSetFile={testDataSetFile}
232226
/>,
233227
);

0 commit comments

Comments
 (0)