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(
() => ({
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;

View File

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

View File

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

View File

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

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 { 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(
{},
{
if (state.loadedPages && state.loadedPages.includes(filters.page)) return;
getResources(filters, {
onCompleted: (resources) => {
const data = Object.assign(resources, { loaded: true });
setList(data);
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 (
<Checkbox
disabled
@ -93,17 +114,64 @@ const ResourcesContainer = () => {
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 (
<>
<PageTitle title="ResourcesX" />
{list.loaded === false ? (
{state.loaded === false ? (
<CircularProgress size={26} />
) : (
<Grid container spacing={4}>
@ -111,14 +179,39 @@ const ResourcesContainer = () => {
<MUIDataTable
title="Resources"
columns={columns}
data={list.values ?? []}
data={state.values ?? []}
options={{
filterType: "textField",
expandableRows: false,
print: false,
selectableRows: false,
rowsPerPage: 10,
rowsPerPageOptions: [10, 20, 50, 100]
selectableRows: "none",
rowsPerPage: state.pageSize,
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>