Skip to content

Commit

Permalink
UIU-3021: add edit user roles accordion to user edit view (#2671)
Browse files Browse the repository at this point in the history
Refs UIU-3021.
  • Loading branch information
aidynoJ authored and ryandberger committed Apr 29, 2024
1 parent bce9a4d commit 49297b5
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
58 changes: 58 additions & 0 deletions src/components/EditSections/EditUserRoles/ EditUserRoles.test.js
Original file line number Diff line number Diff line change
@@ -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(<EditUserRoles accordionId="user-roles" />);

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();
});
});
63 changes: 63 additions & 0 deletions src/components/EditSections/EditUserRoles/EditUserRoles.js
Original file line number Diff line number Diff line change
@@ -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 (
<li
data-test-user-role={role.id}
key={role.id}
>
{role.name}
<Button
buttonStyle="fieldControl"
align="end"
type="button"
id={`clickable-remove-user-role-${role.id}`}
aria-label={`${intl.formatMessage({ id:'ui-users.roles.deleteRole' })}: ${role.name}`}
>
<Icon icon="times-circle" />
</Button>
</li>
);
};

return (
<Accordion
label={<Headline size="large" tag="h3"><FormattedMessage id="ui-users.roles.userRoles" /></Headline>}
id={accordionId}
displayWhenClosed={isLoading ? <Loading /> : <Badge>{userRoles.length}</Badge>}
>
<Row>
<Col xs={12}>
<List
items={userRoles}
itemFormatter={renderRoles}
isEmptyMessage={<FormattedMessage id="ui-users.roles.empty" />}
/>
</Col>
<Button><FormattedMessage id="ui-users.roles.addRoles" /></Button>
<Button><FormattedMessage id="ui-users.roles.unassignAllRoles" /></Button>
</Row>
</Accordion>
);
}

EditUserRoles.propTypes = {
match: PropTypes.shape({ params: { id: PropTypes.string } }),
accordionId: PropTypes.string
};

export default withRouter(EditUserRoles);
58 changes: 58 additions & 0 deletions src/components/EditSections/EditUserRoles/EditUserRoles.test.js
Original file line number Diff line number Diff line change
@@ -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(<EditUserRoles accordionId="user-roles" />);

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();
});
});
1 change: 1 addition & 0 deletions src/components/EditSections/EditUserRoles/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './EditUserRoles';
1 change: 1 addition & 0 deletions src/components/EditSections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
6 changes: 4 additions & 2 deletions src/views/UserEdit/UserForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
EditContactInfo,
EditProxy,
EditServicePoints,
EditUserRoles,
} from '../../components/EditSections';
import { getFullName } from '../../components/util';
import RequestFeeFineBlockButtons from '../../components/RequestFeeFineBlockButtons';
Expand Down Expand Up @@ -380,6 +381,7 @@ class UserForm extends React.Component {
permissions: false,
servicePoints: false,
customFields: true,
userRoles: false
}}
>
<EditUserInfo
Expand Down Expand Up @@ -434,12 +436,12 @@ class UserForm extends React.Component {
)
}
{
this.showPermissionsAccordion() &&
this.showPermissionsAccordion() ?
<TenantsPermissionsAccordion
form={form}
initialValues={initialValues}
setButtonRef={this.setButtonRef}
/>
/> : <EditUserRoles accordionId="userRoles" />
}
<EditServicePoints
accordionId="servicePoints"
Expand Down
11 changes: 9 additions & 2 deletions src/views/UserEdit/UserForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jest.mock(
EditProxy: jest.fn(() => <div>EditProxy accordion</div>),
EditServicePoints: jest.fn(() => <div>EditServicePoints accordion</div>),
EditUserInfo: jest.fn(() => <div>EditUserInfo accordion</div>),
EditUserRoles: jest.fn(() => <div>EditUserRoles accordion</div>)
})
);

Expand Down Expand Up @@ -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(<UserForm {...props} />);

expect(screen.queryByText('TenantsPermissionsAccordion accordion')).toBeInTheDocument();
});

it('show roles accordion when "roles" interface is present', async () => {
props.stripes.hasInterface = () => true;
renderWithRouter(<UserForm {...props} />);

expect(screen.queryByText('Permissions accordion')).toBeFalsy();
expect(screen.queryByText('EditUserRoles accordion')).toBeInTheDocument();
});
});

Expand Down
7 changes: 5 additions & 2 deletions translations/ui-users/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

0 comments on commit 49297b5

Please sign in to comment.