From f946269fef23f141ba1f3719ac080f7aeaa79b9a Mon Sep 17 00:00:00 2001 From: Remko Date: Tue, 17 Oct 2023 13:30:35 +0200 Subject: [PATCH] added pagination limit selector --- pwa/package.json | 6 +- pwa/src/apiService/resources/openWoo.ts | 6 +- .../PaginationLimitSelect.module.css | 12 ++++ .../PaginationLimitSelect.tsx | 72 +++++++++++++++++++ pwa/src/context/global.ts | 3 + pwa/src/context/queryLimit.ts | 24 +++++++ pwa/src/hooks/openWoo.ts | 4 +- pwa/src/templates/landing/LandingTemplate.tsx | 8 ++- pwa/src/translations/en.ts | 3 + pwa/src/translations/nl.ts | 3 + 10 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 pwa/src/components/paginationLimitSelect/PaginationLimitSelect.module.css create mode 100644 pwa/src/components/paginationLimitSelect/PaginationLimitSelect.tsx create mode 100644 pwa/src/context/queryLimit.ts diff --git a/pwa/package.json b/pwa/package.json index 6753018e..ea587d63 100644 --- a/pwa/package.json +++ b/pwa/package.json @@ -22,8 +22,8 @@ "prepare": "cd .. && husky install" }, "dependencies": { - "@conduction/components": "2.2.17", - "@conduction/theme": "1.0.49", + "@conduction/components": "2.2.18", + "@conduction/theme": "1.0.50", "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.4.0", "@fortawesome/react-fontawesome": "^0.1.18", @@ -57,7 +57,7 @@ "@tabler/icons-react": "2.21.0", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", - "@utrecht/component-library-react": "^1.0.0-alpha.355", + "@utrecht/component-library-react": "^1.0.0-alpha.394", "@utrecht/design-tokens": "^1.0.0-alpha.524", "axios": "^0.25.0", "clsx": "^1.1.1", diff --git a/pwa/src/apiService/resources/openWoo.ts b/pwa/src/apiService/resources/openWoo.ts index 91174196..4a2f178f 100644 --- a/pwa/src/apiService/resources/openWoo.ts +++ b/pwa/src/apiService/resources/openWoo.ts @@ -14,8 +14,10 @@ export default class OpenWoo { this._send = send; } - public getAll = async (filters: IFiltersContext, currentPage: number): Promise => { - let endpoint = `/openWOO?extend[]=all${filtersToQueryParams(filters)}&_order[Publicatiedatum]=desc&_limit=${OPEN_WOO_LIMIT}&_page=${currentPage}`; + public getAll = async (filters: IFiltersContext, currentPage: number, limit: number): Promise => { + let endpoint = `/openWOO?extend[]=all${filtersToQueryParams( + filters, + )}&_order[Publicatiedatum]=desc&_limit=${limit}&_page=${currentPage}`; if (process.env.GATSBY_OIDN_NUMBER) { endpoint += `&oidn=${process.env.GATSBY_OIDN_NUMBER}`; diff --git a/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.module.css b/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.module.css new file mode 100644 index 00000000..4357e4cd --- /dev/null +++ b/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.module.css @@ -0,0 +1,12 @@ +.container { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + list-style-type: none; + + padding: 0; + margin: 0; + + user-select: none; +} diff --git a/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.tsx b/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.tsx new file mode 100644 index 00000000..0a516e0d --- /dev/null +++ b/pwa/src/components/paginationLimitSelect/PaginationLimitSelect.tsx @@ -0,0 +1,72 @@ +import * as React from "react"; +import * as styles from "./PaginationLimitSelect.module.css"; +import clsx from "clsx"; +import { useForm } from "react-hook-form"; +import { SelectSingle } from "@conduction/components"; +import { IQueryLimitContext, queryLimitDefault, useQueryLimitContext } from "../../context/queryLimit"; +import { useTranslation } from "react-i18next"; + +interface PaginationLimitSelectProps { + queryLimitName: string; + layoutClassName?: string; +} + +export const PaginationLimitSelectComponent: React.FC = ({ + queryLimitName, + layoutClassName, +}) => { + const { + watch, + register, + control, + setValue, + formState: { errors }, + } = useForm(); + const { queryLimit, setQueryLimit } = useQueryLimitContext(); + const { t } = useTranslation(); + + const watchLimit = watch("limit"); + + const value = queryLimit[queryLimitName as keyof IQueryLimitContext]; + + React.useEffect(() => { + if (!watchLimit) return; + if (parseInt(watchLimit.value) === value) return; + + const selectedLimit = limitSelectOptions.find((LimitOption) => LimitOption.value === watchLimit.value); + + selectedLimit !== undefined && setQueryLimit({ ...queryLimit, [queryLimitName]: parseInt(selectedLimit.value) }); + }, [watchLimit]); + + React.useEffect(() => { + setValue( + "limit", + limitSelectOptions.find((LimitOption) => LimitOption.value === (value !== undefined && value.toString())), + ); + }, []); + + return ( +
+ {`${t("Results per page")}:`} + +
+ ); +}; + +const limitSelectOptions = [ + { label: "6", value: "6" }, + { label: "9", value: "9" }, + { label: "12", value: "12" }, + { label: "21", value: "21" }, + { label: "30", value: "30" }, + { label: "60", value: "60" }, + { label: "120", value: "120" }, +]; diff --git a/pwa/src/context/global.ts b/pwa/src/context/global.ts index c9c3f4b8..189ac629 100644 --- a/pwa/src/context/global.ts +++ b/pwa/src/context/global.ts @@ -3,6 +3,7 @@ import { defaultGatsbyContext, IGatsbyContext } from "./gatsby"; import { defaultFiltersContext, IFiltersContext } from "./filters"; import { defaultDisplayContext, IDisplayContext } from "./displays"; import { defaultPaginationContext, IPaginationContext } from "./pagination"; +import { defaultQueryLimitContext, IQueryLimitContext } from "./queryLimit"; export interface IGlobalContext { initiated: boolean; @@ -10,6 +11,7 @@ export interface IGlobalContext { filters: IFiltersContext; displays: IDisplayContext; pagination: IPaginationContext; + queryLimit: IQueryLimitContext; } export const defaultGlobalContext: IGlobalContext = { @@ -18,6 +20,7 @@ export const defaultGlobalContext: IGlobalContext = { filters: defaultFiltersContext, displays: defaultDisplayContext, pagination: defaultPaginationContext, + queryLimit: defaultQueryLimitContext, }; export const GlobalContext = React.createContext< diff --git a/pwa/src/context/queryLimit.ts b/pwa/src/context/queryLimit.ts new file mode 100644 index 00000000..2a7c021c --- /dev/null +++ b/pwa/src/context/queryLimit.ts @@ -0,0 +1,24 @@ +import * as React from "react"; +import { GlobalContext } from "./global"; + +export const queryLimitDefault = 12; + +export interface IQueryLimitContext { + objectsQueryLimit: number; +} + +export const defaultQueryLimitContext: IQueryLimitContext = { + objectsQueryLimit: queryLimitDefault, +}; + +export const useQueryLimitContext = () => { + const [globalContext, setGlobalContext] = React.useContext(GlobalContext); + + const queryLimit: IQueryLimitContext = globalContext.queryLimit; + + const setQueryLimit = (query: IQueryLimitContext) => { + setGlobalContext((context) => ({ ...context, queryLimit: { ...globalContext.queryLimit, ...query } })); + }; + + return { setQueryLimit, queryLimit }; +}; diff --git a/pwa/src/hooks/openWoo.ts b/pwa/src/hooks/openWoo.ts index e3f7d642..11d6bb03 100644 --- a/pwa/src/hooks/openWoo.ts +++ b/pwa/src/hooks/openWoo.ts @@ -7,8 +7,8 @@ import { IFiltersContext } from "../context/filters"; export const useOpenWoo = (queryClient: QueryClient) => { const API: APIService | null = React.useContext(APIContext); - const getAll = (filters: IFiltersContext, currentPage: number) => - useQuery(["OpenWoo", filters, currentPage], () => API?.OpenWoo.getAll(filters, currentPage), { + const getAll = (filters: IFiltersContext, currentPage: number, limit: number) => + useQuery(["OpenWoo", filters, currentPage, limit], () => API?.OpenWoo.getAll(filters, currentPage, limit), { onError: (error) => { console.warn(error.message); }, diff --git a/pwa/src/templates/landing/LandingTemplate.tsx b/pwa/src/templates/landing/LandingTemplate.tsx index fd8e27be..410e463b 100644 --- a/pwa/src/templates/landing/LandingTemplate.tsx +++ b/pwa/src/templates/landing/LandingTemplate.tsx @@ -11,18 +11,22 @@ import { QueryClient } from "react-query"; import { Pagination } from "@conduction/components"; import { usePaginationContext } from "../../context/pagination"; import { useTranslation } from "react-i18next"; +import { useQueryLimitContext } from "../../context/queryLimit"; +import { PaginationLimitSelectComponent } from "../../components/paginationLimitSelect/PaginationLimitSelect"; export const LandingTemplate: React.FC = () => { const { currentPage, setCurrentPage } = usePaginationContext(); const { filters } = useFiltersContext(); const { t } = useTranslation(); + const { queryLimit } = useQueryLimitContext(); const queryClient = new QueryClient(); - const getItems = useOpenWoo(queryClient).getAll(filters, currentPage); + const getItems = useOpenWoo(queryClient).getAll(filters, currentPage, queryLimit.objectsQueryLimit); return ( <>

+ @@ -39,6 +43,8 @@ export const LandingTemplate: React.FC = () => { totalPages={getItems.data.pages} {...{ currentPage, setCurrentPage }} /> + + )} {getItems.isLoading && } diff --git a/pwa/src/translations/en.ts b/pwa/src/translations/en.ts index 1570bfbd..6189a248 100644 --- a/pwa/src/translations/en.ts +++ b/pwa/src/translations/en.ts @@ -14,6 +14,7 @@ export const en = { Address: "Address", Page: "Page", Jumbotron: "Jumbotron", + Limit: "Limit", "Jumbotron card": "Jumbotron card", "N/A": "N/A", "Details page": "Details page", @@ -51,4 +52,6 @@ export const en = { "Can open a new window": "Can open a new window", "No results found": "No results found", "Enter search query": "Enter search query", + "Results per page": "Results per page", + "Select result limit": "Select result limit", }; diff --git a/pwa/src/translations/nl.ts b/pwa/src/translations/nl.ts index 49eae986..1d862fdd 100644 --- a/pwa/src/translations/nl.ts +++ b/pwa/src/translations/nl.ts @@ -14,6 +14,7 @@ export const nl = { Address: "Adres", Page: "Pagina", Jumbotron: "Jumbotron", + Limit: "Limiet", "Jumbotron card": "Jumbotron tegel", "N/A": "N.v.t", "Details page": "Detailpagina", @@ -51,4 +52,6 @@ export const nl = { "Can open a new window": "Kan een nieuw venster openen", "No results found": "Geen resultaten gevonden", "Enter search query": "Voer zoekopdracht in", + "Results per page": "Resultaten per pagina", + "Select result limit": "Selecteer resultaten limiet", };