diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6710907ec..c13a3de81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
* Validate image url provided as external url for user profile picture. Refs UIU-3080.
* Import and use ProfilePicture Component from stripes/smart-components. Refs UIU-3104.
* Show Roles assigned to users. Refs UIU-3110.
+* Add edit user roles accordion on edit role modal view. Refs UIU-3021.
## [10.1.0](https://github.com/folio-org/ui-users/tree/v10.1.0) (2024-03-20)
[Full Changelog](https://github.com/folio-org/ui-users/compare/v10.0.4...v10.1.0)
diff --git a/src/components/EditSections/EditUserRoles/ EditUserRoles.test.js b/src/components/EditSections/EditUserRoles/ EditUserRoles.test.js
new file mode 100644
index 000000000..7be9f2748
--- /dev/null
+++ b/src/components/EditSections/EditUserRoles/ EditUserRoles.test.js
@@ -0,0 +1,58 @@
+
+import React from 'react';
+import { cleanup } from '@folio/jest-config-stripes/testing-library/react';
+import renderWithRouter from 'helpers/renderWithRouter';
+import {
+ useStripes,
+} from '@folio/stripes/core';
+import EditUserRoles from './EditUserRoles';
+
+import { useUserTenantRoles } from '../../../hooks';
+
+jest.mock('../../../hooks', () => ({
+ ...jest.requireActual('../../../hooks'),
+ useUserTenantRoles: jest.fn(),
+}));
+
+jest.mock('@folio/stripes/core', () => ({
+ ...jest.requireActual('@folio/stripes/core'),
+ useStripes: jest.fn(),
+}));
+
+jest.unmock('@folio/stripes/components');
+
+const STRIPES = {
+ config: {},
+ hasPerm: jest.fn().mockReturnValue(true),
+ okapi: {
+ tenant: 'diku',
+ },
+ user: {
+ user: {
+ consortium: {},
+ },
+ },
+};
+
+
+const renderEditRolesAccordion = () => renderWithRouter();
+
+describe('EditUserRoles Component', () => {
+ beforeEach(() => {
+ useStripes.mockClear().mockReturnValue(STRIPES);
+ useUserTenantRoles.mockClear().mockReturnValue({
+ isFetching: false,
+ userRoles: [{ id: '1', name: 'test role' },
+ { id: '2', name: 'admin role' }
+ ]
+ });
+ });
+ afterEach(cleanup);
+
+ it('shows the list of user roles', () => {
+ const { getByText } = renderEditRolesAccordion();
+
+ expect(getByText('test role')).toBeInTheDocument();
+ expect(getByText('admin role')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/EditSections/EditUserRoles/EditUserRoles.js b/src/components/EditSections/EditUserRoles/EditUserRoles.js
new file mode 100644
index 000000000..0f2774293
--- /dev/null
+++ b/src/components/EditSections/EditUserRoles/EditUserRoles.js
@@ -0,0 +1,63 @@
+import React from 'react';
+import { Accordion, Headline, Badge, Row, Col, List, Button, Icon, Loading } from '@folio/stripes/components';
+import { useIntl, FormattedMessage } from 'react-intl';
+import { withRouter } from 'react-router';
+import PropTypes from 'prop-types';
+import { useStripes } from '@folio/stripes/core';
+import { useUserTenantRoles } from '../../../hooks';
+
+function EditUserRoles({ match, accordionId }) {
+ const { okapi } = useStripes();
+ const intl = useIntl();
+
+ const userId = match.params.id;
+
+ const { userRoles, isLoading } = useUserTenantRoles({ userId, tenantId: okapi.tenant });
+
+ const renderRoles = (role) => {
+ return (
+
+ {role.name}
+
+
+ );
+ };
+
+ return (
+ }
+ id={accordionId}
+ displayWhenClosed={isLoading ? : {userRoles.length}}
+ >
+
+
+
}
+ />
+
+
+
+
+
+ );
+}
+
+EditUserRoles.propTypes = {
+ match: PropTypes.shape({ params: { id: PropTypes.string } }),
+ accordionId: PropTypes.string
+};
+
+export default withRouter(EditUserRoles);
diff --git a/src/components/EditSections/EditUserRoles/EditUserRoles.test.js b/src/components/EditSections/EditUserRoles/EditUserRoles.test.js
new file mode 100644
index 000000000..7be9f2748
--- /dev/null
+++ b/src/components/EditSections/EditUserRoles/EditUserRoles.test.js
@@ -0,0 +1,58 @@
+
+import React from 'react';
+import { cleanup } from '@folio/jest-config-stripes/testing-library/react';
+import renderWithRouter from 'helpers/renderWithRouter';
+import {
+ useStripes,
+} from '@folio/stripes/core';
+import EditUserRoles from './EditUserRoles';
+
+import { useUserTenantRoles } from '../../../hooks';
+
+jest.mock('../../../hooks', () => ({
+ ...jest.requireActual('../../../hooks'),
+ useUserTenantRoles: jest.fn(),
+}));
+
+jest.mock('@folio/stripes/core', () => ({
+ ...jest.requireActual('@folio/stripes/core'),
+ useStripes: jest.fn(),
+}));
+
+jest.unmock('@folio/stripes/components');
+
+const STRIPES = {
+ config: {},
+ hasPerm: jest.fn().mockReturnValue(true),
+ okapi: {
+ tenant: 'diku',
+ },
+ user: {
+ user: {
+ consortium: {},
+ },
+ },
+};
+
+
+const renderEditRolesAccordion = () => renderWithRouter();
+
+describe('EditUserRoles Component', () => {
+ beforeEach(() => {
+ useStripes.mockClear().mockReturnValue(STRIPES);
+ useUserTenantRoles.mockClear().mockReturnValue({
+ isFetching: false,
+ userRoles: [{ id: '1', name: 'test role' },
+ { id: '2', name: 'admin role' }
+ ]
+ });
+ });
+ afterEach(cleanup);
+
+ it('shows the list of user roles', () => {
+ const { getByText } = renderEditRolesAccordion();
+
+ expect(getByText('test role')).toBeInTheDocument();
+ expect(getByText('admin role')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/EditSections/EditUserRoles/index.js b/src/components/EditSections/EditUserRoles/index.js
new file mode 100644
index 000000000..90e31fe29
--- /dev/null
+++ b/src/components/EditSections/EditUserRoles/index.js
@@ -0,0 +1 @@
+export { default } from './EditUserRoles';
diff --git a/src/components/EditSections/index.js b/src/components/EditSections/index.js
index eab6ff9ec..b4dd720a5 100644
--- a/src/components/EditSections/index.js
+++ b/src/components/EditSections/index.js
@@ -3,3 +3,4 @@ export { default as EditExtendedInfo } from './EditExtendedInfo';
export { default as EditProxy } from './EditProxy';
export { default as EditUserInfo } from './EditUserInfo';
export { default as EditServicePoints } from './EditServicePoints';
+export { default as EditUserRoles } from './EditUserRoles';
diff --git a/src/views/UserEdit/UserForm.js b/src/views/UserEdit/UserForm.js
index ddbb06083..beda27582 100644
--- a/src/views/UserEdit/UserForm.js
+++ b/src/views/UserEdit/UserForm.js
@@ -33,6 +33,7 @@ import {
EditContactInfo,
EditProxy,
EditServicePoints,
+ EditUserRoles,
} from '../../components/EditSections';
import { getFullName } from '../../components/util';
import RequestFeeFineBlockButtons from '../../components/RequestFeeFineBlockButtons';
@@ -380,6 +381,7 @@ class UserForm extends React.Component {
permissions: false,
servicePoints: false,
customFields: true,
+ userRoles: false
}}
>
+ /> :
}
EditProxy accordion
),
EditServicePoints: jest.fn(() => EditServicePoints accordion
),
EditUserInfo: jest.fn(() => EditUserInfo accordion
),
+ EditUserRoles: jest.fn(() => EditUserRoles accordion
)
})
);
@@ -190,11 +191,17 @@ describe('UserForm', () => {
expect(screen.getByText('TenantsPermissionsAccordion accordion')).toBeTruthy();
});
- it('omits permissions pane when "roles" interface is present', async () => {
+ it('shows permissions accordion when "roles" interface is NOT present', async () => {
+ renderWithRouter();
+
+ expect(screen.queryByText('TenantsPermissionsAccordion accordion')).toBeInTheDocument();
+ });
+
+ it('show roles accordion when "roles" interface is present', async () => {
props.stripes.hasInterface = () => true;
renderWithRouter();
- expect(screen.queryByText('Permissions accordion')).toBeFalsy();
+ expect(screen.queryByText('EditUserRoles accordion')).toBeInTheDocument();
});
});
diff --git a/translations/ui-users/en.json b/translations/ui-users/en.json
index 1524fecda..0ac9b387f 100644
--- a/translations/ui-users/en.json
+++ b/translations/ui-users/en.json
@@ -1170,6 +1170,9 @@
"patronNoticePrintJobs.created": "Created",
"patronNoticePrintJobs.errors.pdf": "'PDF generation failed",
- "roles.userRoles": "Roles",
- "roles.empty": "No roles found"
+ "roles.userRoles": "User roles",
+ "roles.empty": "No user roles found",
+ "roles.deleteRole": "Delete user role",
+ "roles.addRoles": "Add user roles",
+ "roles.unassignAllRoles": "Unassign all user roles"
}