cdn-frontend/src/features/resources/components/ResourcesContainer.js

309 lines
9.3 KiB
JavaScript

import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Checkbox, FormLabel } from "@material-ui/core";
import MUIDataTable, { debounceSearchRender } from "mui-datatables";
import { LoadingText } from "../../../components";
import PageTitle from "../../../components/PageTitle";
import { useResourcesApi, useDictionariesApi } from "../../../api";
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
import { useTranslation } from "react-i18next";
const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
const __RESOURCE_NAME_MAX_LENGTH = 35;
const ResourcesContainer = () => {
const [state, setState] = useState({
pageSize: 10,
totalCount: 0,
values: []
});
const [loading, setLoading] = useState(false);
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
const [resourceCategories, setResourceCategories] = useState([]);
const { t } = useTranslation();
const { getResources } = useResourcesApi();
const { getResourceCategories } = useDictionariesApi();
useEffect(() => {
getResourceCategories().then((r) => setResourceCategories(r));
}, [getResourceCategories]);
useEffect(() => {
if (filters.loadedPages && filters.loadedPages.includes(filters.page))
return;
setLoading(true);
getResources(filters, {
onCompleted: (resources) => {
setState((prev) => ({
...prev,
...resources,
values: filters.loadedPages
? [...prev.values, ...resources.values]
: resources.values
}));
setFilters((prev) => ({
...prev,
loadedPages: prev?.loadedPages
? [...prev.loadedPages, resources.page]
: [resources.page]
}));
setLoading(false);
}
});
}, [getResources, filters]);
const categoryFilterOptions = useMemo(
() => resourceCategories.map((z) => z.categoryName),
[resourceCategories]
);
const columns = useMemo(
() => [
{
label: t("Resource.Code"),
name: "resourceCode",
options: {
display: true,
draggable: true,
download: true,
print: false,
searchable: true,
sort: true,
customFilterListOptions: {
render: (v) =>
v ? t("Resource.List.Filters.Code", { value: v }) : []
},
filter: true,
filterType: "textField",
filterOptions: {
logic: (_prop, _filterValue, _row) => false
},
filterList: undefined,
hint: undefined
}
},
{
label: t("Resource.Name"),
name: "resourceName",
options: {
display: true,
draggable: true,
download: true,
print: false,
searchable: true,
sort: true,
customBodyRenderLite: (dataIndex, _rowIndex) => {
if (loading) return;
const value = state.values[dataIndex].resourceName;
const formattedValue =
value.length > __RESOURCE_NAME_MAX_LENGTH
? `${value.substring(0, __RESOURCE_NAME_MAX_LENGTH + 1)}[...]`
: value;
return formattedValue;
},
customFilterListOptions: {
render: (v) =>
v ? t("Resource.List.Filters.Name", { value: v }) : []
},
filter: true,
filterType: "textField",
filterOptions: {
logic: (_prop, _filterValue, _row) => false
},
filterList: undefined,
hint: undefined
}
},
{
label: t("Resource.Category"),
name: "categoryName",
options: {
display: true,
draggable: true,
download: true,
print: false,
searchable: true,
sort: true,
filter: true,
customFilterListOptions: {
render: (v) => t("Resource.List.Filters.Category", { value: v })
},
filterType: "dropdown",
filterOptions: {
names: categoryFilterOptions,
logic: (_prop, _filterValue, _row) => false
},
hint: undefined
}
},
{
label: t("Resource.Secured"),
name: "secured",
options: {
display: true,
draggable: true,
download: true,
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>{t("Resource.Secured")}</span> : [];
}
},
filter: true,
filterType: "custom",
filterOptions: {
logic: (_prop, _filterValue, _row) => false,
display: (filterList, onChange, index, column) => {
return (
<div>
<FormLabel>{t("Resource.Secured")}</FormLabel>
<Checkbox
color="primary"
checked={filterList[index][0] || false}
onChange={(event) => {
filterList[index][0] = event.target.checked;
onChange(filterList[index], index, column);
}}
/>
</div>
);
}
},
hint: undefined
}
}
],
[loading, state.values, categoryFilterOptions, t]
);
const changeFilters = useCallback((obj) => {
const keys = Object.keys(obj);
const isPageChange = keys.length === 1 && keys[0] === "page";
if (!isPageChange) {
const { page, loadedPages } = defaultResourcesFilters;
obj = { ...obj, page, loadedPages };
}
setFilters((prev) => ({ ...prev, ...obj }));
}, []);
const getCategoryId = useCallback(
(name) => {
const category = resourceCategories.find((z) => z.categoryName === name);
return category?.categoryId;
},
[resourceCategories]
);
const handleFilterChange = useCallback(
(changedColumn, filterList, type, changedColumnIndex, _displayData) => {
if (type === "reset") {
changeFilters(defaultResourcesFilters);
return;
}
const filterValue = filterList[changedColumnIndex][0];
if (changedColumn === "categoryName") {
const categoryId = filterValue
? getCategoryId(filterValue)
: filterValue;
changeFilters({ categoryId });
return;
}
changeFilters({ [changedColumn]: filterValue });
},
[changeFilters, getCategoryId]
);
return (
<>
<PageTitle title={t("Resource.List.Title")} />
<MUIDataTable
title={t("Resource.List.SubTitle")}
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) =>
changeFilters({ page: currentPage + 1 }),
onChangeRowsPerPage: (numberOfRows) =>
changeFilters({ pageSize: numberOfRows }),
onColumnSortChange: (changedColumn, direction) =>
changeFilters({
sortBy: changedColumn,
sortDirection: direction
}),
onFilterChange: handleFilterChange,
onSearchChange: (text) => changeFilters({ fullTextSearch: text }),
customSort: (data) => data,
customSearch: () => true,
setFilterChipProps: (_colIndex, _colName, _data) => {
return {
color: "primary",
variant: "outlined"
};
},
textLabels: {
body: {
noMatch: loading ? (
<LoadingText lines={15} />
) : (
<>{t("Generic.Table.Body.NoMatch")}</>
)
},
filter: {
all: t("Generic.Table.Filter.All"),
reset: t("Generic.Table.Filter.Reset"),
title: t("Generic.Table.Filter.Title")
},
pagination: {
displayRows: t("Generic.Table.Pagination.DisplayRows"),
next: t("Generic.Table.Pagination.Next"),
previous: t("Generic.Table.Pagination.Previous"),
rowsPerPage: t("Generic.Table.Pagination.RowsPerPage")
},
toolbar: {
downloadCsv: t("Generic.Table.Toolbar.DownloadCsv"),
filterTable: t("Generic.Table.Toolbar.FilterTable"),
print: t("Generic.Table.Toolbar.Print"),
search: t("Generic.Table.Toolbar.Search"),
viewColumns: t("Generic.Table.Toolbar.ViewColumns")
},
viewColumns: {
title: t("Generic.Table.ViewColumns.Title")
}
}
}}
/>
</>
);
};
export default ResourcesContainer;