Compare commits
No commits in common. "f96fe1164b359354b533f6e6aa2858e6a7bc4248" and "f6740853457e5daaf9edda3886ace6da4cd1ac6c" have entirely different histories.
f96fe1164b
...
f674085345
|
@ -1,4 +1,3 @@
|
||||||
import useDictionariesApi from "./useDictionariesApi";
|
|
||||||
import useResourcesApi from "./useResourcesApi";
|
import useResourcesApi from "./useResourcesApi";
|
||||||
|
|
||||||
export { useDictionariesApi, useResourcesApi };
|
export { useResourcesApi };
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { useCallback } from "react";
|
|
||||||
import useHttpRequest from "./useHttpRequest";
|
|
||||||
import { get } from "../utils/axios";
|
|
||||||
|
|
||||||
const cdn = process.env.REACT_APP_CDN_URL;
|
|
||||||
const endpoints = {
|
|
||||||
mimeTypes: `${cdn}/admin/mime-types`
|
|
||||||
};
|
|
||||||
|
|
||||||
const useDictionariesApi = () => {
|
|
||||||
const { exec } = useHttpRequest();
|
|
||||||
|
|
||||||
const getMimeTypes = useCallback(
|
|
||||||
(options) => {
|
|
||||||
const promise = exec(() => get(endpoints.mimeTypes), options);
|
|
||||||
return promise;
|
|
||||||
},
|
|
||||||
[exec]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
getMimeTypes
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useDictionariesApi;
|
|
|
@ -1,47 +0,0 @@
|
||||||
import { useCallback, useMemo } from "react";
|
|
||||||
import { useToast } from "../context/ToastContext";
|
|
||||||
|
|
||||||
const useHttpRequest = () => {
|
|
||||||
const { error } = useToast();
|
|
||||||
|
|
||||||
const handleError = useCallback(
|
|
||||||
(err) => {
|
|
||||||
const message = `${err.title} ${err.correlationId}`;
|
|
||||||
error(message);
|
|
||||||
},
|
|
||||||
[error]
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultOptions = useMemo(
|
|
||||||
() => ({
|
|
||||||
onStart: () => {},
|
|
||||||
onCompleted: () => {},
|
|
||||||
onError: handleError
|
|
||||||
}),
|
|
||||||
[handleError]
|
|
||||||
);
|
|
||||||
|
|
||||||
const exec = useCallback(
|
|
||||||
async (request, options) => {
|
|
||||||
const internalOptions = { ...defaultOptions, ...options };
|
|
||||||
const { onStart, onCompleted, onError } = internalOptions;
|
|
||||||
|
|
||||||
try {
|
|
||||||
onStart();
|
|
||||||
const result = await request();
|
|
||||||
onCompleted(result);
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
onError(error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[defaultOptions]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
exec
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHttpRequest;
|
|
|
@ -1,48 +1,59 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import useHttpRequest from "./useHttpRequest";
|
import { useToast } from "../context/ToastContext";
|
||||||
import { get } from "../utils/axios";
|
import { get, post } 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 endpoints = {
|
||||||
const getResourcesEndpoint = (filters) => {
|
mimeTypes: `${cdn}/admin/mime-types`,
|
||||||
const {
|
resources: `${cdn}/admin/resources`
|
||||||
page,
|
|
||||||
pageSize,
|
|
||||||
sortBy,
|
|
||||||
sortDirection,
|
|
||||||
fullTextSearch,
|
|
||||||
resourceCode,
|
|
||||||
resourceName,
|
|
||||||
categoryId,
|
|
||||||
secured
|
|
||||||
} = filters;
|
|
||||||
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 (resourceName) endpoint += `&ResourceName=${resourceName}`;
|
|
||||||
if (categoryId) endpoint += `&CategoryId=${categoryId}`;
|
|
||||||
if (secured) endpoint += `&Secured=${secured}`;
|
|
||||||
return endpoint;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const useResourcesApi = () => {
|
const useResourcesApi = () => {
|
||||||
const { exec } = useHttpRequest();
|
const { error } = useToast();
|
||||||
|
|
||||||
const getResources = useCallback(
|
const handleError = useCallback(
|
||||||
(filters, options) => {
|
(err) => {
|
||||||
const input = { ...defaultResourcesFilters, ...filters };
|
const message = `${err.title} ${err.correlationId}`;
|
||||||
const endpoint = getResourcesEndpoint(input);
|
error(message);
|
||||||
const promise = exec(() => get(endpoint), options);
|
},
|
||||||
|
[error]
|
||||||
|
);
|
||||||
|
|
||||||
|
const defaultOptions = useMemo(
|
||||||
|
() => ({
|
||||||
|
onCompleted: () => {},
|
||||||
|
onError: handleError
|
||||||
|
}),
|
||||||
|
[handleError]
|
||||||
|
);
|
||||||
|
|
||||||
|
const call = useCallback(
|
||||||
|
async (request, options) => {
|
||||||
|
const internalOptions = { ...defaultOptions, ...options };
|
||||||
|
const { onCompleted, onError } = internalOptions;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await request();
|
||||||
|
onCompleted(result);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
onError(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[defaultOptions]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getMimeTypes = useCallback(
|
||||||
|
(options = defaultOptions) => {
|
||||||
|
const promise = call(() => get(endpoints.mimeTypes), options);
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
[exec]
|
[call, defaultOptions]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getResources
|
getMimeTypes
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ const Content = () => {
|
||||||
[classes.contentShift]: layoutState.isSidebarOpened
|
[classes.contentShift]: layoutState.isSidebarOpened
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div id="fakeToolbar" className={classes.fakeToolbar} />
|
<div 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} />
|
||||||
|
|
|
@ -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(2),
|
marginBottom: theme.spacing(4),
|
||||||
marginTop: theme.spacing(0)
|
marginTop: theme.spacing(5),
|
||||||
},
|
},
|
||||||
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,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
const defaultResourcesFilters = Object.freeze({
|
|
||||||
page: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
sortBy: null,
|
|
||||||
sortDirection: null,
|
|
||||||
fullTextSearch: null,
|
|
||||||
resourceCode: null,
|
|
||||||
resourceName: null,
|
|
||||||
categoryId: null,
|
|
||||||
secured: null
|
|
||||||
});
|
|
||||||
|
|
||||||
export { defaultResourcesFilters };
|
|
|
@ -1,220 +1,20 @@
|
||||||
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
import React, { useState, useEffect } 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 { useResourcesApi } from "../../../api";
|
||||||
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
|
|
||||||
|
|
||||||
const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
|
|
||||||
|
|
||||||
const ResourcesContainer = () => {
|
const ResourcesContainer = () => {
|
||||||
const [state, setState] = useState({ loaded: false, loadedPages: null });
|
const [state, setState] = useState({ loaded: false });
|
||||||
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
|
const { getMimeTypes } = useResourcesApi();
|
||||||
const { getResources } = useResourcesApi();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.loadedPages && state.loadedPages.includes(filters.page)) return;
|
getMimeTypes({
|
||||||
|
onCompleted: (data) => {
|
||||||
getResources(filters, {
|
const dta = Object.assign(data, { loaded: true });
|
||||||
onCompleted: (resources) => {
|
setState(dta);
|
||||||
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, filters, state.loadedPages]);
|
}, [getMimeTypes]);
|
||||||
|
|
||||||
const columns = useMemo(
|
return <div>I'm alive!</div>;
|
||||||
() => [
|
|
||||||
{
|
|
||||||
label: "Code",
|
|
||||||
name: "resourceCode",
|
|
||||||
options: {
|
|
||||||
display: true,
|
|
||||||
draggable: true,
|
|
||||||
download: false,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Name",
|
|
||||||
name: "resourceName",
|
|
||||||
options: {
|
|
||||||
display: true,
|
|
||||||
draggable: true,
|
|
||||||
download: false,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Category",
|
|
||||||
name: "categoryId",
|
|
||||||
options: {
|
|
||||||
display: true,
|
|
||||||
draggable: true,
|
|
||||||
download: false,
|
|
||||||
print: false,
|
|
||||||
searchable: true,
|
|
||||||
sort: true,
|
|
||||||
filter: true,
|
|
||||||
filterType: "dropdown",
|
|
||||||
filterOptions: {
|
|
||||||
logic: (_prop, _filterValue, _row) => false
|
|
||||||
},
|
|
||||||
filterList: [],
|
|
||||||
hint: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Secured",
|
|
||||||
name: "secured",
|
|
||||||
options: {
|
|
||||||
display: true,
|
|
||||||
draggable: true,
|
|
||||||
download: false,
|
|
||||||
print: false,
|
|
||||||
searchable: true,
|
|
||||||
sort: true,
|
|
||||||
customBodyRender: (value, _tableMeta, _updateValue) => {
|
|
||||||
return (
|
|
||||||
<Checkbox
|
|
||||||
disabled
|
|
||||||
size="small"
|
|
||||||
checked={value}
|
|
||||||
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" />
|
|
||||||
{state.loaded === false ? (
|
|
||||||
<CircularProgress size={26} />
|
|
||||||
) : (
|
|
||||||
<MUIDataTable
|
|
||||||
title="Resources"
|
|
||||||
columns={columns}
|
|
||||||
data={state.values ?? []}
|
|
||||||
options={{
|
|
||||||
filterType: "textField",
|
|
||||||
expandableRows: false,
|
|
||||||
print: false,
|
|
||||||
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"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ResourcesContainer;
|
export default ResourcesContainer;
|
||||||
|
|
Loading…
Reference in New Issue