Compare commits

..

No commits in common. "f96fe1164b359354b533f6e6aa2858e6a7bc4248" and "f6740853457e5daaf9edda3886ace6da4cd1ac6c" have entirely different histories.

8 changed files with 63 additions and 339 deletions

View File

@ -1,4 +1,3 @@
import useDictionariesApi from "./useDictionariesApi";
import useResourcesApi from "./useResourcesApi"; import useResourcesApi from "./useResourcesApi";
export { useDictionariesApi, useResourcesApi }; export { useResourcesApi };

View File

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

View File

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

View File

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

View File

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

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(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,
} },
} },
})); }));

View File

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

View File

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