From e3fad73d40c5d38e24bd698583e6b4b503c699c2 Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Thu, 8 Dec 2022 00:53:39 +0200 Subject: [PATCH] resources page --- src/api/useHttpRequest.js | 4 +- src/api/useResourcesApi.js | 20 +-- src/components/Layout/Content.js | 2 +- src/components/PageTitle/styles.js | 14 +- src/constants/resourcesConstants.js | 13 ++ .../components/ResourcesContainer.js | 141 +++++++++++++++--- 6 files changed, 146 insertions(+), 48 deletions(-) create mode 100644 src/constants/resourcesConstants.js diff --git a/src/api/useHttpRequest.js b/src/api/useHttpRequest.js index 5758548..94d2698 100644 --- a/src/api/useHttpRequest.js +++ b/src/api/useHttpRequest.js @@ -14,6 +14,7 @@ const useHttpRequest = () => { const defaultOptions = useMemo( () => ({ + onStart: () => {}, onCompleted: () => {}, onError: handleError }), @@ -23,9 +24,10 @@ const useHttpRequest = () => { const exec = useCallback( async (request, options) => { const internalOptions = { ...defaultOptions, ...options }; - const { onCompleted, onError } = internalOptions; + const { onStart, onCompleted, onError } = internalOptions; try { + onStart(); const result = await request(); onCompleted(result); return result; diff --git a/src/api/useResourcesApi.js b/src/api/useResourcesApi.js index 885e5f1..5906cc6 100644 --- a/src/api/useResourcesApi.js +++ b/src/api/useResourcesApi.js @@ -1,21 +1,10 @@ import { useCallback } from "react"; import useHttpRequest from "./useHttpRequest"; import { get } from "../utils/axios"; +import { defaultResourcesFilters } from "../constants/resourcesConstants"; const cdn = process.env.REACT_APP_CDN_URL; -const defaultResourcesInput = { - page: 1, - pageSize: 10, - sortBy: null, - sortDirection: 0, - fullTextSearch: null, - resourceCode: null, - resourceName: null, - categoryId: null, - secured: null -}; - const getResourcesEndpoint = (filters) => { const { page, @@ -28,11 +17,12 @@ const getResourcesEndpoint = (filters) => { categoryId, secured } = filters; - let endpoint = `${cdn}/admin/resources?Page=${page}&PageSize=${pageSize}&SortDirection=${sortDirection}`; + let endpoint = `${cdn}/admin/resources?Page=${page}&PageSize=${pageSize}`; if (sortBy) endpoint += `&SortBy=${sortBy}`; + if (sortDirection) endpoint += `&SortDirection=${sortDirection}`; if (fullTextSearch) endpoint += `&FullTextSearch=${fullTextSearch}`; if (resourceCode) endpoint += `&ResourceCode=${resourceCode}`; - if (resourceCode) endpoint += `&ResourceName=${resourceName}`; + if (resourceName) endpoint += `&ResourceName=${resourceName}`; if (categoryId) endpoint += `&CategoryId=${categoryId}`; if (secured) endpoint += `&Secured=${secured}`; return endpoint; @@ -43,7 +33,7 @@ const useResourcesApi = () => { const getResources = useCallback( (filters, options) => { - const input = { ...defaultResourcesInput, ...filters }; + const input = { ...defaultResourcesFilters, ...filters }; const endpoint = getResourcesEndpoint(input); const promise = exec(() => get(endpoint), options); return promise; diff --git a/src/components/Layout/Content.js b/src/components/Layout/Content.js index e9038c9..138f563 100644 --- a/src/components/Layout/Content.js +++ b/src/components/Layout/Content.js @@ -33,7 +33,7 @@ const Content = () => { [classes.contentShift]: layoutState.isSidebarOpened })} > -
+
diff --git a/src/components/PageTitle/styles.js b/src/components/PageTitle/styles.js index cc6f3ee..fd2a4bd 100644 --- a/src/components/PageTitle/styles.js +++ b/src/components/PageTitle/styles.js @@ -1,20 +1,20 @@ import { makeStyles } from "@material-ui/styles"; -export default makeStyles(theme => ({ +export default makeStyles((theme) => ({ pageTitleContainer: { display: "flex", justifyContent: "space-between", - marginBottom: theme.spacing(4), - marginTop: theme.spacing(5), + marginBottom: theme.spacing(2), + marginTop: theme.spacing(0) }, typo: { - color: theme.palette.text.hint, + color: theme.palette.text.hint }, button: { boxShadow: theme.customShadows.widget, textTransform: "none", "&:active": { - boxShadow: theme.customShadows.widgetWide, - }, - }, + boxShadow: theme.customShadows.widgetWide + } + } })); diff --git a/src/constants/resourcesConstants.js b/src/constants/resourcesConstants.js new file mode 100644 index 0000000..e857a64 --- /dev/null +++ b/src/constants/resourcesConstants.js @@ -0,0 +1,13 @@ +const defaultResourcesFilters = Object.freeze({ + page: 1, + pageSize: 10, + sortBy: null, + sortDirection: null, + fullTextSearch: null, + resourceCode: null, + resourceName: null, + categoryId: null, + secured: null +}); + +export { defaultResourcesFilters }; diff --git a/src/features/resources/components/ResourcesContainer.js b/src/features/resources/components/ResourcesContainer.js index e749c0d..9d563b1 100644 --- a/src/features/resources/components/ResourcesContainer.js +++ b/src/features/resources/components/ResourcesContainer.js @@ -1,24 +1,34 @@ -import React, { useState, useEffect, useMemo } from "react"; -import { Grid, CircularProgress, Checkbox } from "@material-ui/core"; -import MUIDataTable from "mui-datatables"; +import React, { useState, useEffect, useMemo, useCallback } from "react"; +import { Grid, Checkbox, CircularProgress, FormLabel } from "@material-ui/core"; +import MUIDataTable, { debounceSearchRender } from "mui-datatables"; import PageTitle from "../../../components/PageTitle"; import { useResourcesApi } from "../../../api"; +import { defaultResourcesFilters } from "../../../constants/resourcesConstants"; + +const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100]; const ResourcesContainer = () => { - const [list, setList] = useState({ loaded: false }); + const [state, setState] = useState({ loaded: false, loadedPages: null }); + const [filters, setFilters] = useState({ ...defaultResourcesFilters }); const { getResources } = useResourcesApi(); useEffect(() => { - getResources( - {}, - { - onCompleted: (resources) => { - const data = Object.assign(resources, { loaded: true }); - setList(data); - } + if (state.loadedPages && state.loadedPages.includes(filters.page)) return; + + getResources(filters, { + onCompleted: (resources) => { + const data = { ...resources, loaded: true }; + setState((prev) => ({ + ...prev, + ...data, + values: prev?.values ? [...prev.values, ...data.values] : data.values, + loadedPages: prev?.loadedPages + ? [...prev.loadedPages, data.page] + : [data.page] + })); } - ); - }, [getResources]); + }); + }, [getResources, filters, state.loadedPages]); const columns = useMemo( () => [ @@ -32,8 +42,14 @@ const ResourcesContainer = () => { print: false, searchable: true, sort: true, + customFilterListOptions: { + render: (v) => (v ? `Code contains: ${v}` : []) + }, filter: true, filterType: "textField", + filterOptions: { + logic: (_prop, _filterValue, _row) => false + }, filterList: undefined, hint: undefined } @@ -48,8 +64,14 @@ const ResourcesContainer = () => { print: false, searchable: true, sort: true, + customFilterListOptions: { + render: (v) => (v ? `Name contains: ${v}` : []) + }, filter: true, filterType: "textField", + filterOptions: { + logic: (_prop, _filterValue, _row) => false + }, filterList: undefined, hint: undefined } @@ -66,6 +88,9 @@ const ResourcesContainer = () => { sort: true, filter: true, filterType: "dropdown", + filterOptions: { + logic: (_prop, _filterValue, _row) => false + }, filterList: [], hint: undefined } @@ -80,11 +105,7 @@ const ResourcesContainer = () => { print: false, searchable: true, sort: true, - filter: true, - filterType: "checkbox", - filterList: undefined, - hint: undefined, - customBodyRender: (value, tableMeta, updateValue) => { + customBodyRender: (value, _tableMeta, _updateValue) => { return ( { style={{ padding: "0" }} /> ); - } + }, + customFilterListOptions: { + render: (v) => { + const checked = v[0]; + return checked ? Secured : []; + } + }, + filter: true, + filterType: "custom", + filterOptions: { + logic: (_prop, _filterValue, _row) => false, + display: (filterList, onChange, index, column) => { + return ( +
+ Secured + { + filterList[index][0] = event.target.checked; + onChange(filterList[index], index, column); + }} + /> +
+ ); + } + }, + filterList: undefined, + hint: undefined } } ], [] ); + const handleResetFilters = useCallback(() => { + setFilters((prev) => ({ ...prev, ...defaultResourcesFilters })); + }, [setFilters]); + + const handleFilterChange = useCallback( + (changedColumn, filterList, type, changedColumnIndex, displayData) => { + if (type === "reset") { + handleResetFilters(); + return; + } + const filterValue = filterList[changedColumnIndex][0]; + setFilters((prev) => ({ + ...prev, + [changedColumn]: filterValue + })); + }, + [handleResetFilters] + ); + return ( <> - {list.loaded === false ? ( + {state.loaded === false ? ( ) : ( @@ -111,14 +179,39 @@ const ResourcesContainer = () => { { + setFilters((prev) => ({ ...prev, page: currentPage + 1 })); + }, + onChangeRowsPerPage: (numberOfRows) => { + setFilters((prev) => ({ ...prev, pageSize: numberOfRows })); + }, + onColumnSortChange: (changedColumn, direction) => + setFilters((prev) => ({ + ...prev, + sortBy: changedColumn, + sortDirection: direction + })), + onFilterChange: handleFilterChange, + onSearchChange: (text) => + setFilters((prev) => ({ ...prev, fullTextSearch: text })), + customSort: (data) => data, + customSearch: () => true, + setFilterChipProps: (_colIndex, _colName, _data) => { + return { + color: "primary", + variant: "outlined" + }; + } }} />