resources page

master
Tudor Stanciu 2022-12-08 00:53:39 +02:00
parent 74689dbc93
commit e3fad73d40
6 changed files with 146 additions and 48 deletions

View File

@ -14,6 +14,7 @@ const useHttpRequest = () => {
const defaultOptions = useMemo( const defaultOptions = useMemo(
() => ({ () => ({
onStart: () => {},
onCompleted: () => {}, onCompleted: () => {},
onError: handleError onError: handleError
}), }),
@ -23,9 +24,10 @@ const useHttpRequest = () => {
const exec = useCallback( const exec = useCallback(
async (request, options) => { async (request, options) => {
const internalOptions = { ...defaultOptions, ...options }; const internalOptions = { ...defaultOptions, ...options };
const { onCompleted, onError } = internalOptions; const { onStart, onCompleted, onError } = internalOptions;
try { try {
onStart();
const result = await request(); const result = await request();
onCompleted(result); onCompleted(result);
return result; return result;

View File

@ -1,21 +1,10 @@
import { useCallback } from "react"; import { useCallback } from "react";
import useHttpRequest from "./useHttpRequest"; import useHttpRequest from "./useHttpRequest";
import { get } from "../utils/axios"; import { get } from "../utils/axios";
import { defaultResourcesFilters } from "../constants/resourcesConstants";
const cdn = process.env.REACT_APP_CDN_URL; 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 getResourcesEndpoint = (filters) => {
const { const {
page, page,
@ -28,11 +17,12 @@ const getResourcesEndpoint = (filters) => {
categoryId, categoryId,
secured secured
} = filters; } = 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 (sortBy) endpoint += `&SortBy=${sortBy}`;
if (sortDirection) endpoint += `&SortDirection=${sortDirection}`;
if (fullTextSearch) endpoint += `&FullTextSearch=${fullTextSearch}`; if (fullTextSearch) endpoint += `&FullTextSearch=${fullTextSearch}`;
if (resourceCode) endpoint += `&ResourceCode=${resourceCode}`; if (resourceCode) endpoint += `&ResourceCode=${resourceCode}`;
if (resourceCode) endpoint += `&ResourceName=${resourceName}`; if (resourceName) endpoint += `&ResourceName=${resourceName}`;
if (categoryId) endpoint += `&CategoryId=${categoryId}`; if (categoryId) endpoint += `&CategoryId=${categoryId}`;
if (secured) endpoint += `&Secured=${secured}`; if (secured) endpoint += `&Secured=${secured}`;
return endpoint; return endpoint;
@ -43,7 +33,7 @@ const useResourcesApi = () => {
const getResources = useCallback( const getResources = useCallback(
(filters, options) => { (filters, options) => {
const input = { ...defaultResourcesInput, ...filters }; const input = { ...defaultResourcesFilters, ...filters };
const endpoint = getResourcesEndpoint(input); const endpoint = getResourcesEndpoint(input);
const promise = exec(() => get(endpoint), options); const promise = exec(() => get(endpoint), options);
return promise; return promise;

View File

@ -33,7 +33,7 @@ const Content = () => {
[classes.contentShift]: layoutState.isSidebarOpened [classes.contentShift]: layoutState.isSidebarOpened
})} })}
> >
<div className={classes.fakeToolbar} /> <div id="fakeToolbar" className={classes.fakeToolbar} />
<Switch> <Switch>
<Route path="/dashboard" component={Dashboard} /> <Route path="/dashboard" component={Dashboard} />
<Route path="/resources" component={ResourcesContainer} /> <Route path="/resources" component={ResourcesContainer} />

View File

@ -1,20 +1,20 @@
import { makeStyles } from "@material-ui/styles"; import { makeStyles } from "@material-ui/styles";
export default makeStyles(theme => ({ export default makeStyles((theme) => ({
pageTitleContainer: { pageTitleContainer: {
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
marginBottom: theme.spacing(4), marginBottom: theme.spacing(2),
marginTop: theme.spacing(5), marginTop: theme.spacing(0)
}, },
typo: { typo: {
color: theme.palette.text.hint, color: theme.palette.text.hint
}, },
button: { button: {
boxShadow: theme.customShadows.widget, boxShadow: theme.customShadows.widget,
textTransform: "none", textTransform: "none",
"&:active": { "&:active": {
boxShadow: theme.customShadows.widgetWide, boxShadow: theme.customShadows.widgetWide
}, }
}, }
})); }));

View File

@ -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 };

View File

@ -1,24 +1,34 @@
import React, { useState, useEffect, useMemo } from "react"; import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Grid, CircularProgress, Checkbox } from "@material-ui/core"; import { Grid, Checkbox, CircularProgress, FormLabel } from "@material-ui/core";
import MUIDataTable from "mui-datatables"; import MUIDataTable, { debounceSearchRender } from "mui-datatables";
import PageTitle from "../../../components/PageTitle"; import PageTitle from "../../../components/PageTitle";
import { useResourcesApi } from "../../../api"; import { useResourcesApi } from "../../../api";
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
const ResourcesContainer = () => { const ResourcesContainer = () => {
const [list, setList] = useState({ loaded: false }); const [state, setState] = useState({ loaded: false, loadedPages: null });
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
const { getResources } = useResourcesApi(); const { getResources } = useResourcesApi();
useEffect(() => { useEffect(() => {
getResources( if (state.loadedPages && state.loadedPages.includes(filters.page)) return;
{},
{ getResources(filters, {
onCompleted: (resources) => { onCompleted: (resources) => {
const data = Object.assign(resources, { loaded: true }); const data = { ...resources, loaded: true };
setList(data); setState((prev) => ({
...prev,
...data,
values: prev?.values ? [...prev.values, ...data.values] : data.values,
loadedPages: prev?.loadedPages
? [...prev.loadedPages, data.page]
: [data.page]
}));
} }
} });
); }, [getResources, filters, state.loadedPages]);
}, [getResources]);
const columns = useMemo( const columns = useMemo(
() => [ () => [
@ -32,8 +42,14 @@ const ResourcesContainer = () => {
print: false, print: false,
searchable: true, searchable: true,
sort: true, sort: true,
customFilterListOptions: {
render: (v) => (v ? `Code contains: ${v}` : [])
},
filter: true, filter: true,
filterType: "textField", filterType: "textField",
filterOptions: {
logic: (_prop, _filterValue, _row) => false
},
filterList: undefined, filterList: undefined,
hint: undefined hint: undefined
} }
@ -48,8 +64,14 @@ const ResourcesContainer = () => {
print: false, print: false,
searchable: true, searchable: true,
sort: true, sort: true,
customFilterListOptions: {
render: (v) => (v ? `Name contains: ${v}` : [])
},
filter: true, filter: true,
filterType: "textField", filterType: "textField",
filterOptions: {
logic: (_prop, _filterValue, _row) => false
},
filterList: undefined, filterList: undefined,
hint: undefined hint: undefined
} }
@ -66,6 +88,9 @@ const ResourcesContainer = () => {
sort: true, sort: true,
filter: true, filter: true,
filterType: "dropdown", filterType: "dropdown",
filterOptions: {
logic: (_prop, _filterValue, _row) => false
},
filterList: [], filterList: [],
hint: undefined hint: undefined
} }
@ -80,11 +105,7 @@ const ResourcesContainer = () => {
print: false, print: false,
searchable: true, searchable: true,
sort: true, sort: true,
filter: true, customBodyRender: (value, _tableMeta, _updateValue) => {
filterType: "checkbox",
filterList: undefined,
hint: undefined,
customBodyRender: (value, tableMeta, updateValue) => {
return ( return (
<Checkbox <Checkbox
disabled disabled
@ -93,17 +114,64 @@ const ResourcesContainer = () => {
style={{ padding: "0" }} style={{ padding: "0" }}
/> />
); );
},
customFilterListOptions: {
render: (v) => {
const checked = v[0];
return checked ? <span>Secured</span> : [];
} }
},
filter: true,
filterType: "custom",
filterOptions: {
logic: (_prop, _filterValue, _row) => false,
display: (filterList, onChange, index, column) => {
return (
<div>
<FormLabel>Secured</FormLabel>
<Checkbox
color="primary"
checked={filterList[index][0] || false}
onChange={(event) => {
filterList[index][0] = event.target.checked;
onChange(filterList[index], index, column);
}}
/>
</div>
);
}
},
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 ( return (
<> <>
<PageTitle title="ResourcesX" /> <PageTitle title="ResourcesX" />
{list.loaded === false ? ( {state.loaded === false ? (
<CircularProgress size={26} /> <CircularProgress size={26} />
) : ( ) : (
<Grid container spacing={4}> <Grid container spacing={4}>
@ -111,14 +179,39 @@ const ResourcesContainer = () => {
<MUIDataTable <MUIDataTable
title="Resources" title="Resources"
columns={columns} columns={columns}
data={list.values ?? []} data={state.values ?? []}
options={{ options={{
filterType: "textField", filterType: "textField",
expandableRows: false, expandableRows: false,
print: false, print: false,
selectableRows: false, selectableRows: "none",
rowsPerPage: 10, rowsPerPage: state.pageSize,
rowsPerPageOptions: [10, 20, 50, 100] rowsPerPageOptions: __ROWS_PER_PAGE_OPTIONS,
count: state.totalCount,
customSearchRender: debounceSearchRender(500),
onChangePage: (currentPage) => {
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"
};
}
}} }}
/> />
</Grid> </Grid>