From fd78a0328076ecbfffc3d306af50ff4c5d3428a3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 6 Mar 2024 00:23:38 +0100 Subject: [PATCH] move pagination state entirely to URL params don't duplicate it state variables --- jsx/src/Store.js | 39 +------ jsx/src/components/Groups/Groups.jsx | 45 +------- .../ServerDashboard/ServerDashboard.jsx | 100 ++++-------------- jsx/src/util/paginationParams.js | 63 +++++++++++ 4 files changed, 91 insertions(+), 156 deletions(-) create mode 100644 jsx/src/util/paginationParams.js diff --git a/jsx/src/Store.js b/jsx/src/Store.js index f933fdfb..fd8b5833 100644 --- a/jsx/src/Store.js +++ b/jsx/src/Store.js @@ -1,55 +1,20 @@ export const initialState = { user_data: undefined, - user_page: { offset: 0, limit: window.api_page_limit || 100 }, - name_filter: "", + user_page: undefined, groups_data: undefined, - groups_page: { offset: 0, limit: window.api_page_limit || 100 }, + groups_page: undefined, limit: window.api_page_limit || 100, }; export const reducers = (state = initialState, action) => { switch (action.type) { // Updates the client user model data and stores the page - case "USER_OFFSET": - return Object.assign({}, state, { - user_page: Object.assign({}, state.user_page, { - offset: action.value.offset, - }), - }); - - case "USER_LIMIT": - return Object.assign({}, state, { - user_page: Object.assign({}, state.user_page, { - limit: action.value.limit, - }), - }); - - case "USER_NAME_FILTER": - // set offset to 0 if name filter changed, - // otherwise leave it alone - const newOffset = - action.value.name_filter !== state.name_filter ? 0 : state.name_filter; - return Object.assign({}, state, { - user_page: Object.assign({}, state.user_page, { - offset: newOffset, - }), - name_filter: action.value.name_filter, - }); - case "USER_PAGE": return Object.assign({}, state, { user_page: action.value.page, user_data: action.value.data, }); - // Updates the client group user model data and stores the page - case "GROUPS_OFFSET": - return Object.assign({}, state, { - groups_page: Object.assign({}, state.groups_page, { - offset: action.value.offset, - }), - }); - case "GROUPS_PAGE": return Object.assign({}, state, { groups_page: action.value.page, diff --git a/jsx/src/components/Groups/Groups.jsx b/jsx/src/components/Groups/Groups.jsx index e6332dbc..257caf6c 100644 --- a/jsx/src/components/Groups/Groups.jsx +++ b/jsx/src/components/Groups/Groups.jsx @@ -1,7 +1,6 @@ import React, { useEffect } from "react"; import { useSelector, useDispatch } from "react-redux"; import PropTypes from "prop-types"; -import { debounce } from "lodash"; import { Link } from "react-router-dom"; import { useSearchParams } from "react-router-dom-v5-compat"; @@ -12,49 +11,15 @@ const Groups = (props) => { groups_page = useSelector((state) => state.groups_page), dispatch = useDispatch(); - let [searchParams, setSearchParams] = useSearchParams(); - - var offset = parseInt(searchParams.get("offset", "0")) || 0; - var limit = parseInt(searchParams.get("limit", "0")) || window.api_page_limit; - - const setOffset = (offset) => { - console.log("setting offset", offset); - if (offset < 0) { - offset = 0; - } - setSearchParams((params) => { - params.set("offset", offset); - return params; - }); - dispatch({ - type: "GROUPS_OFFSET", - value: { - offset: offset, - }, - }); - }; - - const setLimit = (newLimit) => { - if (newLimit < 1) { - newLimit = 10; - } - setSearchParams((params) => { - params.set("limit", newLimit); - return params; - }); - dispatch({ - type: "GROUP_LIMIT", - value: { - limit: newLimit, - }, - }); - }; + const { setOffset, offset, setLimit, handleLimit, limit, setPagination } = + usePaginationParams(); var total = groups_page ? groups_page.total : undefined; var { updateGroups, history } = props; const dispatchPageUpdate = (data, page) => { + setPagination(page); dispatch({ type: "GROUPS_PAGE", value: { @@ -74,10 +39,6 @@ const Groups = (props) => { return
; } - const handleLimit = debounce(async (event) => { - setLimit(event.target.value); - }, 300); - return (
diff --git a/jsx/src/components/ServerDashboard/ServerDashboard.jsx b/jsx/src/components/ServerDashboard/ServerDashboard.jsx index a82d2de5..d2bdaee2 100644 --- a/jsx/src/components/ServerDashboard/ServerDashboard.jsx +++ b/jsx/src/components/ServerDashboard/ServerDashboard.jsx @@ -22,6 +22,7 @@ import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa"; import "./server-dashboard.css"; import { timeSince } from "../../util/timeSince"; +import { usePaginationParams } from "../../util/paginationParams"; import PaginationFooter from "../PaginationFooter/PaginationFooter"; const RowListItem = ({ text }) => ( @@ -32,10 +33,10 @@ RowListItem.propTypes = { }; const ServerDashboard = (props) => { - let base_url = window.base_url || "/"; - let [searchParams, setSearchParams] = useSearchParams(); + const base_url = window.base_url || "/"; + const [searchParams, setSearchParams] = useSearchParams(); // sort methods - var usernameDesc = (e) => e.sort((a, b) => (a.name > b.name ? 1 : -1)), + const usernameDesc = (e) => e.sort((a, b) => (a.name > b.name ? 1 : -1)), usernameAsc = (e) => e.sort((a, b) => (a.name < b.name ? 1 : -1)), adminDesc = (e) => e.sort((a) => (a.admin ? -1 : 1)), adminAsc = (e) => e.sort((a) => (a.admin ? 1 : -1)), @@ -50,20 +51,19 @@ const ServerDashboard = (props) => { runningAsc = (e) => e.sort((a) => (a.server == null ? -1 : 1)), runningDesc = (e) => e.sort((a) => (a.server == null ? 1 : -1)); - var [errorAlert, setErrorAlert] = useState(null); - var [sortMethod, setSortMethod] = useState(null); - var [collapseStates, setCollapseStates] = useState({}); + const [errorAlert, setErrorAlert] = useState(null); + const [sortMethod, setSortMethod] = useState(null); + const [collapseStates, setCollapseStates] = useState({}); - var user_data = useSelector((state) => state.user_data), - user_page = useSelector((state) => state.user_page), - name_filter = useSelector((state) => state.name_filter); + const user_data = useSelector((state) => state.user_data); + const user_page = useSelector((state) => state.user_page); - // get offset, limit, name filter from URL - var offset = parseInt(searchParams.get("offset", "0")) || 0; - var limit = parseInt(searchParams.get("limit", "0")) || window.api_page_limit; - var searchNameFilter = searchParams.get("name_filter"); + const { setOffset, offset, setLimit, handleLimit, limit, setPagination } = + usePaginationParams(); - var total = user_page ? user_page.total : undefined; + const name_filter = searchParams.get("name_filter"); + + const total = user_page ? user_page.total : undefined; const dispatch = useDispatch(); @@ -79,6 +79,7 @@ const ServerDashboard = (props) => { } = props; const dispatchPageUpdate = (data, page) => { + setPagination(page); dispatch({ type: "USER_PAGE", value: { @@ -88,49 +89,15 @@ const ServerDashboard = (props) => { }); }; - const setOffset = (newOffset) => { - if (newOffset < 0) { - newOffset = 0; - } - setSearchParams((params) => { - params.set("offset", newOffset); - return params; - }); - dispatch({ - type: "USER_OFFSET", - value: { - offset: newOffset, - }, - }); - }; - - const setLimit = (newLimit) => { - if (newLimit < 1) { - newLimit = 10; - } - setSearchParams((params) => { - params.set("limit", newLimit); - return params; - }); - dispatch({ - type: "USER_LIMIT", - value: { - limit: newLimit, - }, - }); - }; - const setNameFilter = (name_filter) => { setSearchParams((params) => { - params.set("name_filter", name_filter); + if (name_filter) { + params.set("name_filter", name_filter); + } else { + params.delete("name_filter"); + } return params; }); - dispatch({ - type: "USER_NAME_FILTER", - value: { - name_filter: name_filter, - }, - }); }; useEffect(() => { @@ -139,11 +106,6 @@ const ServerDashboard = (props) => { .catch((err) => setErrorAlert("Failed to update user list.")); }, [offset, limit, name_filter]); - if (searchNameFilter && name_filter != searchNameFilter) { - // get name_filter from URL - setNameFilter(searchNameFilter); - } - if (!user_data || !user_page) { return
; } @@ -154,10 +116,6 @@ const ServerDashboard = (props) => { setNameFilter(event.target.value); }, 300); - const handleLimit = debounce(async (event) => { - setLimit(event.target.value); - }, 300); - if (sortMethod != null) { user_data = sortMethod(user_data); } @@ -175,11 +133,7 @@ const ServerDashboard = (props) => { if (res.status < 300) { updateUsers(...slice) .then((data) => { - dispatchPageUpdate( - data.items, - data._pagination, - name_filter, - ); + dispatchPageUpdate(data.items, data._pagination); }) .catch(() => { setIsDisabled(false); @@ -537,11 +491,7 @@ const ServerDashboard = (props) => { .then((res) => { updateUsers(...slice) .then((data) => { - dispatchPageUpdate( - data.items, - data._pagination, - name_filter, - ); + dispatchPageUpdate(data.items, data._pagination); }) .catch(() => setErrorAlert(`Failed to update users list.`), @@ -577,11 +527,7 @@ const ServerDashboard = (props) => { .then((res) => { updateUsers(...slice) .then((data) => { - dispatchPageUpdate( - data.items, - data._pagination, - name_filter, - ); + dispatchPageUpdate(data.items, data._pagination); }) .catch(() => setErrorAlert(`Failed to update users list.`), diff --git a/jsx/src/util/paginationParams.js b/jsx/src/util/paginationParams.js new file mode 100644 index 00000000..7fe97381 --- /dev/null +++ b/jsx/src/util/paginationParams.js @@ -0,0 +1,63 @@ +import { debounce } from "lodash"; +import { useSearchParams } from "react-router-dom-v5-compat"; + +export const usePaginationParams = () => { + // get offset, limit, name filter from URL + const [searchParams, setSearchParams] = useSearchParams(); + const offset = parseInt(searchParams.get("offset", "0")) || 0; + const limit = + parseInt(searchParams.get("limit", "0")) || window.api_page_limit; + + const _setOffset = (params, offset) => { + if (offset < 0) offset = 0; + if (offset === 0) { + params.delete("offset"); + } else { + params.set("offset", offset); + } + }; + const _setLimit = (params, limit) => { + if (limit < 10) limit = 10; + if (limit === window.api_page_limit) { + params.delete("limit"); + } else { + params.set("limit", limit); + } + }; + const setPagination = (pagination) => { + // update pagination in one + setSearchParams((params) => { + _setOffset(params, pagination.offset); + _setLimit(params, pagination.limit); + return params; + }); + }; + + const setOffset = (offset) => { + if (offset < 0) offset = 0; + setSearchParams((params) => { + _setOffset(params, offset); + return params; + }); + }; + + const setLimit = (limit) => { + setSearchParams((params) => { + _setLimit(params, limit); + return params; + }); + }; + + const handleLimit = debounce(async (event) => { + setLimit(event.target.value); + }, 300); + + return { + offset, + setOffset, + limit, + setLimit, + handleLimit, + setPagination, + }; +};