diff --git a/src/features/resources/api/useResourcesApi.js b/src/features/resources/api/useResourcesApi.js
index 9dc1c1e..ce54d41 100644
--- a/src/features/resources/api/useResourcesApi.js
+++ b/src/features/resources/api/useResourcesApi.js
@@ -1,6 +1,6 @@
import { useCallback } from "react";
import useHttpRequest from "../../../hooks/useHttpRequest";
-import { get } from "../../../utils/axios";
+import { get, del } from "../../../utils/axios";
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
const cdn = process.env.REACT_APP_CDN_URL;
@@ -50,9 +50,19 @@ const useResourcesApi = () => {
[exec]
);
+ const deleteResource = useCallback(
+ (resourceId, options) => {
+ const endpoint = `${cdn}/admin/resource?ResourceId=${resourceId}`;
+ const promise = exec(() => del(endpoint), options);
+ return promise;
+ },
+ [exec]
+ );
+
return {
getResources,
- getResource
+ getResource,
+ deleteResource
};
};
diff --git a/src/features/resources/edit/components/DeleteDialog.js b/src/features/resources/edit/components/DeleteDialog.js
new file mode 100644
index 0000000..886d0e3
--- /dev/null
+++ b/src/features/resources/edit/components/DeleteDialog.js
@@ -0,0 +1,43 @@
+import React from "react";
+import PropTypes from "prop-types";
+import Button from "@material-ui/core/Button";
+import Dialog from "@material-ui/core/Dialog";
+import DialogActions from "@material-ui/core/DialogActions";
+import DialogContent from "@material-ui/core/DialogContent";
+import DialogContentText from "@material-ui/core/DialogContentText";
+import DialogTitle from "@material-ui/core/DialogTitle";
+
+const DeleteDialog = ({ open, onClose, onConfirm, title }) => {
+ return (
+
+ );
+};
+
+DeleteDialog.propTypes = {
+ open: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onConfirm: PropTypes.func.isRequired,
+ title: PropTypes.string.isRequired
+};
+
+export default DeleteDialog;
diff --git a/src/features/resources/edit/components/MimeTypeComponent.js b/src/features/resources/edit/components/MimeTypeComponent.js
index 0f013ca..157778a 100644
--- a/src/features/resources/edit/components/MimeTypeComponent.js
+++ b/src/features/resources/edit/components/MimeTypeComponent.js
@@ -19,8 +19,8 @@ const MimeTypeComponent = ({ mimeType, mimeTypes, onPropertyChange }) => {
{isAutomaticMimeType ? (
{
color="primary"
/>
}
- label="Auto mime type"
+ label="Auto MIME type"
/>
>
diff --git a/src/features/resources/edit/components/ResourceComponent.js b/src/features/resources/edit/components/ResourceComponent.js
index bd8cd61..9810f64 100644
--- a/src/features/resources/edit/components/ResourceComponent.js
+++ b/src/features/resources/edit/components/ResourceComponent.js
@@ -1,85 +1,173 @@
import React from "react";
import PropTypes from "prop-types";
-import { Grid, Paper, ButtonBase, TextField } from "@material-ui/core";
+import {
+ Grid,
+ Paper,
+ ButtonBase,
+ TextField,
+ FormControlLabel,
+ Checkbox,
+ Button
+} from "@material-ui/core";
+import Autocomplete from "@material-ui/lab/Autocomplete";
+import { Save as SaveIcon, Delete as DeleteIcon } from "@material-ui/icons";
import { makeStyles } from "@material-ui/core/styles";
import style from "../styles";
import ResourcePreviewComponent from "./ResourcePreviewComponent";
import MimeTypeComponent from "./MimeTypeComponent";
+import DeleteDialog from "./DeleteDialog";
import { onTextFieldChange } from "../../../../utils/adapters";
const useStyles = makeStyles(style);
-const ResourceComponent = ({ resource, mimeTypes, onPropertyChange }) => {
+const ResourceComponent = ({
+ resource,
+ mimeTypes,
+ resourceCategories,
+ onPropertyChange,
+ deleteProps,
+ processing
+}) => {
const classes = useStyles();
return (
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ onPropertyChange("categoryId")(value.categoryId)
+ }
+ getOptionLabel={(option) => {
+ const optionIsObject =
+ typeof option === "object" && option !== null;
+ if (optionIsObject) return option.categoryName;
+
+ const category = resourceCategories.find(
+ (z) => z.categoryId === option
+ );
+ return category.categoryName;
+ }}
+ getOptionSelected={(option, value) =>
+ option.categoryId === value
+ }
+ renderInput={(params) => (
+
+ )}
+ />
+
+
+
+ onPropertyChange("secured")(event.target.checked)
+ }
+ name="resources-is-secured"
+ color="primary"
+ />
+ }
+ label="Secured"
+ />
+
-
-
-
-
-
-
-
+
+
+
+
+ }
+ onClick={deleteProps.onOpen}
+ disabled={!!processing}
+ >
+ {processing === "delete" ? "Deleting" : "Delete"}
+
+ }
+ disabled={!!processing}
+ >
+ {processing === "delete" ? "Saving" : "Save"}
+
+
+
-
-
-
-
-
+
+
+ >
);
};
ResourceComponent.propTypes = {
resource: PropTypes.object.isRequired,
mimeTypes: PropTypes.array.isRequired,
- onPropertyChange: PropTypes.func.isRequired
+ resourceCategories: PropTypes.array.isRequired,
+ onPropertyChange: PropTypes.func.isRequired,
+ deleteProps: PropTypes.object.isRequired,
+ processing: PropTypes.bool.isRequired
};
export default ResourceComponent;
diff --git a/src/features/resources/edit/components/ResourceContainer.js b/src/features/resources/edit/components/ResourceContainer.js
index ceb473f..e6ccea1 100644
--- a/src/features/resources/edit/components/ResourceContainer.js
+++ b/src/features/resources/edit/components/ResourceContainer.js
@@ -6,18 +6,23 @@ import { LoadingText } from "../../../../components";
import ResourceComponent from "./ResourceComponent";
import { makeStyles } from "@material-ui/core/styles";
import style from "../styles";
+import { useToast } from "../../../../hooks";
const useStyles = makeStyles(style);
const ResourceContainer = () => {
const [state, setState] = useState(null);
const [loading, setLoading] = useState(false);
- const [mimeTypes, setMimeTypes] = useState([]);
+ const [mimeTypes, setMimeTypes] = useState(null);
+ const [resourceCategories, setResourceCategories] = useState(null);
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
+ const [processing, setProcessing] = useState(null);
const classes = useStyles();
const params = useParams();
- const { getResource } = useResourcesApi();
- const { getMimeTypes } = useDictionariesApi();
+ const { getResource, deleteResource } = useResourcesApi();
+ const { getMimeTypes, getResourceCategories } = useDictionariesApi();
+ const { success } = useToast();
const isNew = useMemo(() => params.id === "new", [params.id]);
@@ -25,6 +30,10 @@ const ResourceContainer = () => {
getMimeTypes().then((r) => setMimeTypes(r));
}, [getMimeTypes]);
+ useEffect(() => {
+ getResourceCategories().then((r) => setResourceCategories(r));
+ }, [getResourceCategories]);
+
useEffect(() => {
if (isNew) return;
const resourceId = parseInt(params.id);
@@ -39,7 +48,17 @@ const ResourceContainer = () => {
setState((prev) => ({ ...prev, [prop]: value }));
};
- if (loading || state === null) return ;
+ const handleDelete = async (resourceId) => {
+ setProcessing("delete");
+ const response = await deleteResource(resourceId);
+ if (response && response.resourceId === state.resourceId)
+ success(`Resource '${state.resourceName}' was successfully deleted.`);
+ setProcessing(null);
+ setDeleteDialogOpen(false);
+ };
+
+ if (loading || !state || !mimeTypes || !resourceCategories)
+ return ;
return (
<>
@@ -48,7 +67,15 @@ const ResourceContainer = () => {
setDeleteDialogOpen(true),
+ onClose: () => setDeleteDialogOpen(false),
+ onConfirm: () => handleDelete(state.resourceId)
+ }}
+ processing={processing}
/>
>
diff --git a/src/features/resources/edit/styles.js b/src/features/resources/edit/styles.js
index 1bba25a..4a7d6e2 100644
--- a/src/features/resources/edit/styles.js
+++ b/src/features/resources/edit/styles.js
@@ -12,6 +12,9 @@ const style = (theme) => {
display: "block",
maxWidth: "100%",
maxHeight: "100%"
+ },
+ button: {
+ marginRight: theme.spacing(1)
}
};
};
diff --git a/src/hooks/useHttpRequest.js b/src/hooks/useHttpRequest.js
index 8a523e5..85b999a 100644
--- a/src/hooks/useHttpRequest.js
+++ b/src/hooks/useHttpRequest.js
@@ -6,7 +6,24 @@ const useHttpRequest = () => {
const handleError = useCallback(
(err) => {
- const message = `${err.title} ${err.correlationId}`;
+ let message;
+ switch (err?.statusCode) {
+ case 500:
+ message = "Internal server error.";
+ break;
+
+ case 404:
+ message = err.serverMessage;
+ break;
+
+ case 401:
+ message = `Unauthorized: ${err.serverMessage}`;
+ break;
+
+ default:
+ message = "An unexpected error has occurred.";
+ }
+
error(message);
},
[error]