From 26b9febc48ac3ad9b49016834f06a73258dfd9b3 Mon Sep 17 00:00:00 2001 From: Hege Aalvik Date: Wed, 18 Oct 2023 13:52:46 +0200 Subject: [PATCH] feat: add pagination --- package-lock.json | 46 +++++++++---------- src/api/community-api/search.ts | 5 +- src/components/with-community/index.tsx | 12 ++--- .../with-community/redux/actions.ts | 14 +++--- .../with-community/redux/reducer.ts | 7 +-- src/components/with-community/redux/saga.ts | 13 +++--- src/pages/requests/index.tsx | 44 +++++++++++++++--- src/pages/requests/styled.ts | 37 ++++++++++++++- src/types/domain.d.ts | 9 ++-- 9 files changed, 127 insertions(+), 60 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3aaa92503..ec0f5b60d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -488,11 +488,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.22.15", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -631,12 +631,12 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -853,9 +853,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2201,18 +2201,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", - "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", + "@babel/generator": "^7.23.0", "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.22.5", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.16", - "@babel/types": "^7.22.19", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2221,12 +2221,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.19", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", - "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.19", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { diff --git a/src/api/community-api/search.ts b/src/api/community-api/search.ts index 2a448818b..50fa234bb 100644 --- a/src/api/community-api/search.ts +++ b/src/api/community-api/search.ts @@ -42,18 +42,19 @@ export const extractTopicsFromSearch = ( export const searchCommunityRequests = ( queryTerm: string, + page: number, sortOption?: string ) => { if (queryTerm.length > 0) { return axios .get( - `${FDK_COMMUNITY_BASE_URI}/api/search?term=${queryTerm}&in=titles&matchWords=all&categories[]=6&sortBy=${sortOption}&sortDirection=desc` + `${FDK_COMMUNITY_BASE_URI}/api/search?term=${queryTerm}&in=titles&matchWords=all&categories[]=6&sortBy=${sortOption}&sortDirection=desc&page=${page}` ) .then(({ data }) => data); } return axios .get( - `${FDK_COMMUNITY_BASE_URI}/api/search?&categories[]=6&sortBy=${sortOption}&sortDirection=desc` + `${FDK_COMMUNITY_BASE_URI}/api/search?&categories[]=6&sortBy=${sortOption}&sortDirection=desc&page=${page}` ) .then(({ data }) => data); }; diff --git a/src/components/with-community/index.tsx b/src/components/with-community/index.tsx index 1f60cb002..a2b5ce95b 100644 --- a/src/components/with-community/index.tsx +++ b/src/components/with-community/index.tsx @@ -4,18 +4,15 @@ import { connect } from 'react-redux'; import * as actions from './redux/actions'; -import type { - CommunityPost, - CommunityRequestCategory, - CommunityTopic -} from '../../types'; +import type { CommunityPost, CommunityTopic, Pagination } from '../../types'; export interface Props { topics: CommunityTopic[]; multiplePages: boolean; posts: CommunityPost[]; communityActions: typeof actions; - requests: CommunityRequestCategory; + requests: CommunityTopic[]; + pagination: Pagination; } const withCommunity = (Component: ComponentType) => { @@ -25,7 +22,8 @@ const withCommunity = (Component: ComponentType) => { topics: state.CommunityReducer.get('topics').toJS(), multiplePages: state.CommunityReducer.get('multiplePages'), posts: state.CommunityReducer.get('posts').toJS(), - requests: state.CommunityReducer.get('requests').toJS() + requests: state.CommunityReducer.get('requests').toJS(), + pagination: state.CommunityReducer.get('pagination').toJS() }); const mapDispatchToProps = (dispatch: Dispatch) => ({ diff --git a/src/components/with-community/redux/actions.ts b/src/components/with-community/redux/actions.ts index e92c0ec61..3209643c3 100644 --- a/src/components/with-community/redux/actions.ts +++ b/src/components/with-community/redux/actions.ts @@ -12,7 +12,7 @@ import { SEARCH_REQUESTS_FAILED } from './action-types'; -import type { CommunityPost, CommunityTopic } from '../../../types'; +import type { CommunityPost, CommunityTopic, Pagination } from '../../../types'; import { CommunityTerm } from '../../../types/enums'; export function searchTopicsRequested(queryTerm: string) { @@ -48,26 +48,28 @@ export function searchTopicsFailed(message: string) { export function searchRequestsRequested( queryTerm: string, + page: number, sortOption?: string ) { return { type: SEARCH_REQUESTS_REQUESTED, payload: { queryTerm, - sortOption + sortOption, + page } }; } export function searchRequestsSucceeded( - topics: CommunityTopic[], - multiplePages: boolean + requests: CommunityTopic[], + pagination: Pagination ) { return { type: SEARCH_REQUESTS_SUCCEEDED, payload: { - topics, - multiplePages + requests, + pagination } }; } diff --git a/src/components/with-community/redux/reducer.ts b/src/components/with-community/redux/reducer.ts index 2fe42147a..50705140b 100644 --- a/src/components/with-community/redux/reducer.ts +++ b/src/components/with-community/redux/reducer.ts @@ -21,7 +21,8 @@ const initialState = fromJS({ topics: [], multiplePages: false, posts: [], - requests: {} + requests: [], + pagination: {} }); export default function reducer( @@ -49,8 +50,8 @@ export default function reducer( return state.set('topics', fromJS([])); case SEARCH_REQUESTS_SUCCEEDED: return state - .set('topics', fromJS(action.payload.topics)) - .set('multiplePages', fromJS(action.payload.multiplePages)); + .set('requests', fromJS(action.payload.requests)) + .set('pagination', fromJS(action.payload.pagination)); case SEARCH_REQUESTS_FAILED: default: return state; diff --git a/src/components/with-community/redux/saga.ts b/src/components/with-community/redux/saga.ts index 5a97a9cf7..6caeff590 100644 --- a/src/components/with-community/redux/saga.ts +++ b/src/components/with-community/redux/saga.ts @@ -43,16 +43,17 @@ function* searchTopicsRequested({ } function* searchRequestsRequested({ - payload: { queryTerm, sortOption } + payload: { queryTerm, sortOption, page } }: ReturnType) { try { const postHits: CommunityPost = yield call( searchCommunityRequests, queryTerm, + page, sortOption ); - const { multiplePages } = postHits; - const topics: CommunityTopic[] = ( + const { pagination } = postHits; + const requests: CommunityTopic[] = ( (yield all( extractTopicsFromSearch(postHits).map(({ tid }) => call(getTopicById, tid) @@ -60,13 +61,13 @@ function* searchRequestsRequested({ )) as CommunityTopic[] ).filter(Boolean); - if (topics.length > 0) { - yield put(actions.searchTopicsSucceeded(topics, multiplePages)); + if (requests.length > 0) { + yield put(actions.searchRequestsSucceeded(requests, pagination)); } else { yield put(actions.searchTopicsFailed('')); } } catch (e: any) { - yield put(actions.searchTopicsFailed(e.message)); + yield put(actions.searchRequestsFailed(e.message)); } } diff --git a/src/pages/requests/index.tsx b/src/pages/requests/index.tsx index 66b6a1efb..fc7202ece 100644 --- a/src/pages/requests/index.tsx +++ b/src/pages/requests/index.tsx @@ -12,19 +12,21 @@ import { formatDate } from '../../lib/date-utils'; import Banner from '../../components/banner'; import localization from '../../lib/localization'; import env from '../../env'; +import ReactPaginate from 'react-paginate'; const { FDK_COMMUNITY_BASE_URI } = env; interface Props extends CommunityProps {} const RequestsPage: FC = ({ - topics, + requests, + pagination, communityActions: { searchRequestsRequested } }) => { useEffect(() => { - searchRequestsRequested(''); + searchRequestsRequested('', 1); }, []); - const notDeletedRequests = topics?.filter(topic => topic.deleted === 0); + const notDeletedRequests = requests?.filter(topic => topic.deleted === 0); const [search, setSearch] = useState(''); return ( @@ -56,15 +58,19 @@ const RequestsPage: FC = ({ - @@ -74,7 +80,9 @@ const RequestsPage: FC = ({ type='text' onChange={event => setSearch(event.target.value)} /> - + @@ -100,6 +108,28 @@ const RequestsPage: FC = ({ {topic.viewcount} ))} + + { + searchRequestsRequested(search, data.selected + 1); + }} + previousLabel={ + <> + + {localization.page.prev} + + } + nextLabel={ + <> + {localization.page.next} + + + } + /> + +

{localization.requestsPage.requestData}

diff --git a/src/pages/requests/styled.ts b/src/pages/requests/styled.ts index 892096e03..9d33647fe 100755 --- a/src/pages/requests/styled.ts +++ b/src/pages/requests/styled.ts @@ -1,4 +1,6 @@ import styled from 'styled-components'; +import ArrowRightIconBase from '@fellesdatakatalog/icons/assets/svg/arrow-right-stroke.svg'; +import ArrowLeftIconBase from '@fellesdatakatalog/icons/assets/svg/arrow-left-stroke.svg'; const RequestRow = styled.div` display: flex; @@ -77,6 +79,36 @@ const Text = styled.div` } `; +const ArrowRightIcon = styled(ArrowRightIconBase)` + width: 16px; + height: 16px; + margin-left: 0.25em; + & * { + stroke: #0069a5; + } +`; + +const ArrowLeftIcon = styled(ArrowLeftIconBase)` + width: 16px; + height: 16px; + margin-right: 0.25em; + & * { + stroke: #0069a5; + } +`; + +const Pagination = styled.div` + & > ul { + display: flex; + justify-content: center; + align-items: center; + } + + & > ul > li { + padding: 10px; + } +`; + export default { RequestRow, RequestsTitleRow, @@ -88,5 +120,8 @@ export default { Button, InfoBox, Text, - FirstRow + FirstRow, + ArrowLeftIcon, + ArrowRightIcon, + Pagination }; diff --git a/src/types/domain.d.ts b/src/types/domain.d.ts index 9b87387c0..36f119b82 100644 --- a/src/types/domain.d.ts +++ b/src/types/domain.d.ts @@ -1017,13 +1017,12 @@ export interface CommunityPost { index: number; page?: number; multiplePages: boolean; + pagination: Pagination; } -export interface CommunityRequestCategory { - description: string; - name: string; - post_count: number; - topics: CommunityRequest[]; +export interface Pagination { + currentPage: number; + pageCount: number; } export interface CommunityRequest {