diff --git a/packages/web/src/components/ConfirmationDialog/index.jsx b/packages/web/src/components/ConfirmationDialog/index.jsx
index abc5cd71..61cff3ae 100644
--- a/packages/web/src/components/ConfirmationDialog/index.jsx
+++ b/packages/web/src/components/ConfirmationDialog/index.jsx
@@ -6,6 +6,7 @@ import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
+import Alert from '@mui/material/Alert';
function ConfirmationDialog(props) {
const {
@@ -16,6 +17,7 @@ function ConfirmationDialog(props) {
cancelButtonChildren,
confirmButtonChildren,
open = true,
+ errorMessage,
} = props;
const dataTest = props['data-test'];
return (
@@ -44,6 +46,11 @@ function ConfirmationDialog(props) {
)}
+ {errorMessage && (
+
+ {errorMessage}
+
+ )}
);
}
@@ -57,6 +64,7 @@ ConfirmationDialog.propTypes = {
confirmButtonChildren: PropTypes.node.isRequired,
open: PropTypes.bool,
'data-test': PropTypes.string,
+ errorMessage: PropTypes.string,
};
export default ConfirmationDialog;
diff --git a/packages/web/src/components/DeleteRoleButton/index.ee.jsx b/packages/web/src/components/DeleteRoleButton/index.ee.jsx
index 5a40c1f9..4e70c34d 100644
--- a/packages/web/src/components/DeleteRoleButton/index.ee.jsx
+++ b/packages/web/src/components/DeleteRoleButton/index.ee.jsx
@@ -4,6 +4,7 @@ import IconButton from '@mui/material/IconButton';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import * as React from 'react';
+import { getGeneralErrorMessage, getFieldErrorMessage } from 'helpers/errors';
import Can from 'components/Can';
import ConfirmationDialog from 'components/ConfirmationDialog';
import useFormatMessage from 'hooks/useFormatMessage';
@@ -15,7 +16,21 @@ function DeleteRoleButton(props) {
const formatMessage = useFormatMessage();
const enqueueSnackbar = useEnqueueSnackbar();
- const { mutateAsync: deleteRole } = useAdminDeleteRole(roleId);
+ const {
+ mutateAsync: deleteRole,
+ error: deleteRoleError,
+ reset: resetDeleteRole,
+ } = useAdminDeleteRole(roleId);
+
+ const roleErrorMessage = getFieldErrorMessage({
+ fieldName: 'role',
+ error: deleteRoleError,
+ });
+
+ const generalErrorMessage = getGeneralErrorMessage({
+ error: deleteRoleError,
+ fallbackMessage: formatMessage('deleteRoleButton.generalError'),
+ });
const handleConfirm = React.useCallback(async () => {
try {
@@ -28,24 +43,14 @@ function DeleteRoleButton(props) {
'data-test': 'snackbar-delete-role-success',
},
});
- } catch (error) {
- const errors = Object.values(
- error.response.data.errors || [['Failed while deleting!']],
- );
-
- for (const [error] of errors) {
- enqueueSnackbar(error, {
- variant: 'error',
- SnackbarProps: {
- 'data-test': 'snackbar-delete-role-error',
- },
- });
- }
-
- throw new Error('Failed while deleting!');
- }
+ } catch {}
}, [deleteRole, enqueueSnackbar, formatMessage]);
+ const handleClose = () => {
+ setShowConfirmation(false);
+ resetDeleteRole();
+ };
+
return (
<>
@@ -65,11 +70,12 @@ function DeleteRoleButton(props) {
open={showConfirmation}
title={formatMessage('deleteRoleButton.title')}
description={formatMessage('deleteRoleButton.description')}
- onClose={() => setShowConfirmation(false)}
+ onClose={handleClose}
onConfirm={handleConfirm}
cancelButtonChildren={formatMessage('deleteRoleButton.cancel')}
confirmButtonChildren={formatMessage('deleteRoleButton.confirm')}
data-test="delete-role-modal"
+ errorMessage={roleErrorMessage || generalErrorMessage}
/>
>
);
diff --git a/packages/web/src/components/DeleteUserButton/index.ee.jsx b/packages/web/src/components/DeleteUserButton/index.ee.jsx
index de4b918f..96ea717f 100644
--- a/packages/web/src/components/DeleteUserButton/index.ee.jsx
+++ b/packages/web/src/components/DeleteUserButton/index.ee.jsx
@@ -3,6 +3,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
import IconButton from '@mui/material/IconButton';
import { useQueryClient } from '@tanstack/react-query';
+import { getGeneralErrorMessage } from 'helpers/errors';
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
import * as React from 'react';
import ConfirmationDialog from 'components/ConfirmationDialog';
@@ -12,12 +13,21 @@ import useAdminUserDelete from 'hooks/useAdminUserDelete';
function DeleteUserButton(props) {
const { userId } = props;
const [showConfirmation, setShowConfirmation] = React.useState(false);
- const { mutateAsync: deleteUser } = useAdminUserDelete(userId);
+ const {
+ mutateAsync: deleteUser,
+ error: deleteUserError,
+ reset: resetDeleteUser,
+ } = useAdminUserDelete(userId);
const formatMessage = useFormatMessage();
const enqueueSnackbar = useEnqueueSnackbar();
const queryClient = useQueryClient();
+ const generalErrorMessage = getGeneralErrorMessage({
+ error: deleteUserError,
+ fallbackMessage: formatMessage('deleteUserButton.deleteError'),
+ });
+
const handleConfirm = React.useCallback(async () => {
try {
await deleteUser();
@@ -29,16 +39,14 @@ function DeleteUserButton(props) {
'data-test': 'snackbar-delete-user-success',
},
});
- } catch (error) {
- enqueueSnackbar(
- error?.message || formatMessage('deleteUserButton.deleteError'),
- {
- variant: 'error',
- },
- );
- }
+ } catch {}
}, [deleteUser]);
+ const handleClose = () => {
+ setShowConfirmation(false);
+ resetDeleteUser();
+ };
+
return (
<>
setShowConfirmation(false)}
+ onClose={handleClose}
onConfirm={handleConfirm}
cancelButtonChildren={formatMessage('deleteUserButton.cancel')}
confirmButtonChildren={formatMessage('deleteUserButton.confirm')}
data-test="delete-user-modal"
+ errorMessage={generalErrorMessage}
/>
>
);
diff --git a/packages/web/src/helpers/errors.js b/packages/web/src/helpers/errors.js
new file mode 100644
index 00000000..a872a8b6
--- /dev/null
+++ b/packages/web/src/helpers/errors.js
@@ -0,0 +1,29 @@
+// Helpers to extract errors received from the API
+
+export const getGeneralErrorMessage = ({ error, fallbackMessage }) => {
+ if (!error) {
+ return;
+ }
+
+ const errors = error?.response?.data?.errors;
+ const generalError = errors?.general;
+
+ if (generalError && Array.isArray(generalError)) {
+ return generalError.join(' ');
+ }
+
+ if (!errors) {
+ return error?.message || fallbackMessage;
+ }
+};
+
+export const getFieldErrorMessage = ({ fieldName, error }) => {
+ const errors = error?.response?.data?.errors;
+ const fieldErrors = errors?.[fieldName];
+
+ if (fieldErrors && Array.isArray(fieldErrors)) {
+ return fieldErrors.join(', ');
+ }
+
+ return '';
+};
diff --git a/packages/web/src/locales/en.json b/packages/web/src/locales/en.json
index b121f5e2..24d7c546 100644
--- a/packages/web/src/locales/en.json
+++ b/packages/web/src/locales/en.json
@@ -245,6 +245,7 @@
"deleteRoleButton.cancel": "Cancel",
"deleteRoleButton.confirm": "Delete",
"deleteRoleButton.successfullyDeleted": "The role has been deleted.",
+ "deleteRoleButton.generalError": "Failed while deleting!",
"editRolePage.title": "Edit role",
"createRolePage.title": "Create role",
"roleForm.name": "Name",