diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json
index 4871139..7e92947 100644
--- a/public/locales/en/translations.json
+++ b/public/locales/en/translations.json
@@ -37,5 +37,15 @@
"IncorrectCredentials": "Incorrect credentials.",
"Hello": "Hi, {{username}}",
"AuthenticationDate": "Authentication date"
+ },
+ "Resource": {
+ "Code": "Code",
+ "Name": "Name",
+ "Category": "Category",
+ "Secured": "Secured",
+ "CodeContains": "Code contains: {{value}}",
+ "NameContains": "Name contains: {{value}}",
+ "CategoryChip": "Category: {{value}}",
+ "ListTitle": "Resource management"
}
}
diff --git a/src/components/LoadingContent/LoadingText.js b/src/components/LoadingContent/LoadingText.js
new file mode 100644
index 0000000..215fc85
--- /dev/null
+++ b/src/components/LoadingContent/LoadingText.js
@@ -0,0 +1,48 @@
+import React from "react";
+import PropTypes from "prop-types";
+import grey from "@material-ui/core/colors/grey";
+import { Paper, makeStyles } from "@material-ui/core";
+
+const styles = {
+ cover: {
+ width: "100%"
+ },
+ bar: {
+ backgroundColor: grey[200],
+ height: 10,
+ margin: 20,
+ "&:nth-child(2n)": {
+ marginRight: "20%"
+ }
+ },
+ paper: {
+ padding: "10px",
+ borderRadius: "6px"
+ }
+};
+
+const useStyles = makeStyles(styles);
+
+const LoadingText = ({ lines = 4, onPaper = false, ...props }) => {
+ const classes = useStyles();
+ const loadingText = (
+
+ {[...Array(lines)].map((_e, i) => (
+
+ ))}
+
+ );
+
+ if (onPaper) {
+ return {loadingText};
+ }
+
+ return loadingText;
+};
+
+LoadingText.propTypes = {
+ lines: PropTypes.number,
+ onPaper: PropTypes.bool
+};
+
+export default LoadingText;
diff --git a/src/components/index.js b/src/components/index.js
new file mode 100644
index 0000000..963082e
--- /dev/null
+++ b/src/components/index.js
@@ -0,0 +1,3 @@
+import LoadingText from "./LoadingContent/LoadingText";
+
+export { LoadingText };
diff --git a/src/features/resources/components/ResourcesContainer.js b/src/features/resources/components/ResourcesContainer.js
index a3e1197..8fb4be9 100644
--- a/src/features/resources/components/ResourcesContainer.js
+++ b/src/features/resources/components/ResourcesContainer.js
@@ -1,12 +1,14 @@
import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Checkbox, FormLabel } from "@material-ui/core";
import MUIDataTable, { debounceSearchRender } from "mui-datatables";
-import Skeleton from "@material-ui/lab/Skeleton";
+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({
@@ -18,6 +20,7 @@ const ResourcesContainer = () => {
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
const [resourceCategories, setResourceCategories] = useState([]);
+ const { t } = useTranslation();
const { getResources } = useResourcesApi();
const { getResourceCategories } = useDictionariesApi();
@@ -52,10 +55,15 @@ const ResourcesContainer = () => {
});
}, [getResources, filters]);
+ const categoryFilterOptions = useMemo(
+ () => resourceCategories.map((z) => z.categoryName),
+ [resourceCategories]
+ );
+
const columns = useMemo(
() => [
{
- label: "Code",
+ label: t("Resource.Code"),
name: "resourceCode",
options: {
display: true,
@@ -65,7 +73,7 @@ const ResourcesContainer = () => {
searchable: true,
sort: true,
customFilterListOptions: {
- render: (v) => (v ? `Code contains: ${v}` : [])
+ render: (v) => (v ? t("Resource.CodeContains", { value: v }) : [])
},
filter: true,
filterType: "textField",
@@ -77,7 +85,7 @@ const ResourcesContainer = () => {
}
},
{
- label: "Name",
+ label: t("Resource.Name"),
name: "resourceName",
options: {
display: true,
@@ -86,8 +94,17 @@ const ResourcesContainer = () => {
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 ? `Name contains: ${v}` : [])
+ render: (v) => (v ? t("Resource.NameContains", { value: v }) : [])
},
filter: true,
filterType: "textField",
@@ -99,7 +116,7 @@ const ResourcesContainer = () => {
}
},
{
- label: "Category",
+ label: t("Resource.Category"),
name: "categoryName",
options: {
display: true,
@@ -109,16 +126,19 @@ const ResourcesContainer = () => {
searchable: true,
sort: true,
filter: true,
+ customFilterListOptions: {
+ render: (v) => t("Resource.CategoryChip", { value: v })
+ },
filterType: "dropdown",
filterOptions: {
+ names: categoryFilterOptions,
logic: (_prop, _filterValue, _row) => false
},
- filterList: [],
hint: undefined
}
},
{
- label: "Secured",
+ label: t("Resource.Secured"),
name: "secured",
options: {
display: true,
@@ -140,7 +160,7 @@ const ResourcesContainer = () => {
customFilterListOptions: {
render: (v) => {
const checked = v[0];
- return checked ? Secured : [];
+ return checked ? {t("Resource.Secured")} : [];
}
},
filter: true,
@@ -150,7 +170,7 @@ const ResourcesContainer = () => {
display: (filterList, onChange, index, column) => {
return (
-
Secured
+
{t("Resource.Secured")}
{
);
}
},
- filterList: undefined,
hint: undefined
}
}
],
- []
+ [loading, state.values, categoryFilterOptions, t]
);
const changeFilters = useCallback((obj) => {
@@ -182,21 +201,39 @@ const ResourcesContainer = () => {
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) => {
+ (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]
+ [changeFilters, getCategoryId]
);
return (
<>
-
+
{
textLabels: {
body: {
noMatch: loading ? (
-
+
) : (
- "Sorry, there is no matching data to display"
+ "Sorry, no matching records found"
)
}
}