Skip to content

Commit

Permalink
UIU-3115 - reading room acecss acoordion on user edit view
Browse files Browse the repository at this point in the history
  • Loading branch information
Terala-Priyanka committed May 21, 2024
1 parent ac8d11e commit 56277f9
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* *BREAKING* Add new okapi interface reading-room-patron-permission. Create new permission 'Users: Can view reading room access'. Refs UIU-3116.
* Create new permission 'Users: Can view, and edit reading room access'. Refs UIU-3117.
* Include DCB in 'User Type' search filter group. Refs UIU-3016.
* Implement Reading Room Access functionality in user profile edit. Refs UIU-3115.

## [10.1.1](https://github.com/folio-org/ui-users/tree/v10.1.1) (2024-05-07)
[Full Changelog](https://github.com/folio-org/ui-users/compare/v10.1.0...v10.1.1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { noop } from 'lodash';

import {
Accordion,
Headline,
MultiColumnList,
} from '@folio/stripes/components';
import { useStripes } from '@folio/stripes/core';

import { rraColumns } from './constants';
import { getFormatter } from './getFormatter';

const EditReadingRoomAccess = ({
expanded,
onToggle,
accordionId,
form,
formData,
}) => {
const stripes = useStripes();
const columnMapping = {
[rraColumns.ACCESS]: <FormattedMessage id="ui-users.readingRoom.access" />,
[rraColumns.READING_ROOM_NAME]: <FormattedMessage id="ui-users.readingRoom.name" />,
[rraColumns.NOTES]: <FormattedMessage id="ui-users.readingRoom.note" />,
};
const visibleColumns = Object.keys(columnMapping);
const readOnly = !stripes.hasPerm('reading-room-patron-permission.item.put');

useEffect(() => {
const unregisterReadingRoomAccessList = form.registerField('readingRoomsAccessList', noop, { initialValue: [] });
return () => {
unregisterReadingRoomAccessList();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<Accordion
open={expanded}
id={accordionId}
onToggle={onToggle}
label={<Headline size="large" tag="h3"><FormattedMessage id="ui-users.readingRoom.readingRoomAccess" /></Headline>}
displayWhenClosed={formData.length}
>
<MultiColumnList
striped
contentData={formData}
columnMapping={columnMapping}
visibleColumns={visibleColumns}
formatter={getFormatter(form, readOnly)}
/>
</Accordion>
);
};

EditReadingRoomAccess.propTypes = {
expanded: PropTypes.bool,
onToggle: PropTypes.func,
accordionId: PropTypes.string.isRequired,
formData: PropTypes.object,
form: PropTypes.object,
};

export default EditReadingRoomAccess;
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { screen, waitFor } from '@folio/jest-config-stripes/testing-library/react';
import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
import { within } from '@folio/jest-config-stripes/testing-library/dom';
import { Form } from 'react-final-form';

import renderWithRouter from 'helpers/renderWithRouter';
import '../../../../test/jest/__mock__/matchMedia.mock';

import EditReadingRoomAccess from './EditReadingRoomAccess';

jest.unmock('@folio/stripes/components');

const unregisterFieldMock = jest.fn();

const onSubmit = jest.fn();
const arrayMutators = {
concat: jest.fn(),
move: jest.fn(),
pop: jest.fn(),
push: jest.fn(),
remove: jest.fn(),
removeBatch: jest.fn(),
shift: jest.fn(),
swap: jest.fn(),
unshift: jest.fn(),
update: jest.fn()
};
const renderEditReadingRoomAccess = (props, initialValues) => {
const component = () => (
<>
<EditReadingRoomAccess {...props} />
</>
);
renderWithRouter(
<Form
id="form-user"
mutators={{
...arrayMutators
}}
initialValues={initialValues}
onSubmit={onSubmit}
render={component}
/>
);
};

const props = {
expanded: true,
onToggle: jest.fn(),
accordionId: 'readingRoomAccess',
form: {
change: jest.fn(),
registerField: jest.fn().mockReturnValue(unregisterFieldMock),
},
formData: [
{
'id': '2205004b-ca51-4a14-87fd-938eefa8f5df',
'userId': '2205005b-ca51-4a04-87fd-938eefa8f6de',
'readingRoomId': 'ea7ac988-ede1-466b-968c-46a770333b14',
'readingRoomName': 'rr-4',
'access': 'ALLOWED',
'notes': 'Allowed for this reading room...',
'metadata': {
'createdDate': '2024-05-15 18:39:31',
'createdByUserId': '21457ab5-4635-4e56-906a-908f05e9233b',
'updatedDate': '2024-05-15 18:40:27',
'updatedByUserId': '21457ab5-4635-4e56-906a-908f05e9233b'
}
},
{
'id': 'fe1d83dc-e3f9-4e57-aa2c-0b245ae7eb19',
'userId': '2205005b-ca51-4a04-87fd-938eefa8f6de',
'readingRoomId': '754c6287-892c-4484-941a-23e050fc8888',
'readingRoomName': 'abc',
'access': 'NOT_ALLOWED',
'notes': '',
'metadata': {
'createdDate': '2024-05-21 07:05:17',
'createdByUserId': '21457ab5-4635-4e56-906a-908f05e9233b',
'updatedDate': '2024-05-21 07:13:11',
'updatedByUserId': '21457ab5-4635-4e56-906a-908f05e9233b'
}
}
],
};
describe('EditReadingRoomAccess', () => {
it('should render component', () => {
renderEditReadingRoomAccess(props);
expect(screen.getByText('ui-users.readingRoom.readingRoomAccess')).toBeDefined();
});

it('should display columns - access, name and note', () => {
renderEditReadingRoomAccess(props);
[
'ui-users.readingRoom.access',
'ui-users.readingRoom.name',
'ui-users.readingRoom.note',
].forEach(col => expect(screen.getByText(col)).toBeDefined());
});

it('should update the notes', async () => {
renderEditReadingRoomAccess(props);
const noteField1 = document.querySelectorAll('[id^=textarea]')[0];
await userEvent.type(noteField1, 'note1');
await waitFor(() => expect(props.form.change).toHaveBeenCalled());
});

it('should update access', async () => {
renderEditReadingRoomAccess(props);
const accessSelectField = document.querySelectorAll('[id=reading-room-access-select]')[0];
await userEvent.click(accessSelectField);
const list = screen.getByRole('listbox');
await userEvent.click(within(list).getByText('Not allowed', { exact: false }));
await waitFor(() => expect(props.form.change).toHaveBeenCalled());
});
});
17 changes: 17 additions & 0 deletions src/components/EditSections/EditReadingRoomAccess/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const rraColumns = {
ACCESS: 'access',
READING_ROOM_NAME: 'readingRoomName',
NOTES: 'notes',
};

// TODO: Translations to be applied to the options
export const READING_ROOM_ACCESS_OPTIONS = [
{
label: 'Allowed',
value: 'ALLOWED'
},
{
label: 'Not allowed',
value: 'NOT_ALLOWED'
}
];
69 changes: 69 additions & 0 deletions src/components/EditSections/EditReadingRoomAccess/getFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-disable import/prefer-default-export */
import PropTypes from 'prop-types';
import { Field } from 'react-final-form';
import { cloneDeep } from 'lodash';
import { v4 as uuidv4 } from 'uuid';

import { Selection, TextArea } from '@folio/stripes/components';

import { rraColumns, READING_ROOM_ACCESS_OPTIONS } from './constants';

export const getFormatter = (form, readOnly) => {
const updateRecord = (record, val, name, rowIndex) => {
const clonedRecord = cloneDeep(record);
clonedRecord[name] = val;
if (!clonedRecord.id) {
clonedRecord.id = uuidv4();
}
form.change(`readingRoomsAccessList[${rowIndex}]`, clonedRecord);
};

return ({
[rraColumns.ACCESS] : Object.assign(
({ rowIndex, ...record }) => (
<Field
name={`${rraColumns.ACCESS}`}
id={`${rraColumns.ACCESS}-${rowIndex}`}
aria-label={`${rraColumns.ACCESS}-${rowIndex}`}
render={({ input }) => {
return (
<Selection
ariaLabel="reading-room access"
dataOptions={READING_ROOM_ACCESS_OPTIONS}
id="reading-room-access-select"
disabled={readOnly}
value={record.access}
onChange={(val) => {
updateRecord(record, val, input.name, rowIndex);
}}
/>
);
}}
/>
),
{ rowIndex: PropTypes.number, record: PropTypes.object }
),
[rraColumns.READING_ROOM_NAME] : ({ readingRoomName }) => readingRoomName,
[rraColumns.NOTES] : Object.assign(
({ rowIndex, ...record }) => (
<Field
name={`${rraColumns.NOTES}`}
ariaLabel={`${rraColumns.NOTES}-${rowIndex}`}
id={`${rraColumns.NOTES}-${rowIndex}`}
render={({ input }) => (
<TextArea
{...input}
fullWidth
value={record?.notes}
disabled={readOnly}
onChange={(e) => {
updateRecord(record, e.target.value, input.name, rowIndex);
}}
/>
)}
/>
),
{ rowIndex: PropTypes.number, record: PropTypes.object }
)
});
};
1 change: 1 addition & 0 deletions src/components/EditSections/EditReadingRoomAccess/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './EditReadingRoomAccess';
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 EditReadingRoomAccess } from './EditReadingRoomAccess';
9 changes: 9 additions & 0 deletions src/routes/UserRecordContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ class UserRecordContainer extends React.Component {
path: 'configurations/entries?query=module=="@folio/users" AND configName=="suppressEdit"',
records: 'configs',
},
userReadingRoomPermissions: {
type: 'okapi',
// eslint-disable-next-line consistent-return
path: (queryParams, pathComponents, resourceData, config, props) => {
if (props.stripes.hasPerm('reading-room.patron-permission.item.get') && pathComponents.id) {
return `reading-room-patron-permission/${pathComponents.id}`;
}
}
},
});

static propTypes = {
Expand Down
22 changes: 20 additions & 2 deletions src/views/UserEdit/UserEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class UserEdit extends React.Component {
'addressTypes',
'servicePoints',
'departments',
'userReadingRoomPermissions'
);

return formData;
Expand Down Expand Up @@ -201,7 +202,19 @@ class UserEdit extends React.Component {
return copiedCustomFields;
}

update({ requestPreferences, ...userFormData }) {
updateUserReadingRoomAccess(list) {
const { mutator } = this.props;
// collect the values in the list and make a PUT request
const payload = list.filter(rra => rra && rra);

mutator.userReadingRoomPermissions.PUT(payload)
.then((resp) => {
console.log('response ', resp);

Check warning on line 212 in src/views/UserEdit/UserEdit.js

View workflow job for this annotation

GitHub Actions / build-npm

Unexpected console statement

Check warning on line 212 in src/views/UserEdit/UserEdit.js

View workflow job for this annotation

GitHub Actions / build-npm

Unexpected console statement
// history.push(`/users/preview/${user.id}${search}`);
}).catch((e) => showErrorCallout(e, this.context.sendCallout));
}

update({ requestPreferences, readingRoomsAccessList, ...userFormData }) {
const {
updateProxies,
updateSponsors,
Expand All @@ -220,6 +233,11 @@ class UserEdit extends React.Component {
const user = cloneDeep(userFormData);
const prevUser = resources?.selUser?.records?.[0] ?? {};

// update user reading room access
if (get(resources, 'userReadingRoomPermissions') && readingRoomsAccessList?.length > 0) {
this.updateUserReadingRoomAccess(readingRoomsAccessList);
}

if (get(resources, 'requestPreferences.records[0].totalRecords')) {
this.updateRequestPreferences(requestPreferences);
} else {
Expand All @@ -246,7 +264,7 @@ class UserEdit extends React.Component {
updateServicePoints(servicePoints, preferredServicePoint);
}

const data = omit(user, ['creds', 'proxies', 'sponsors', 'permissions', 'servicePoints', 'preferredServicePoint']);
const data = omit(user, ['creds', 'proxies', 'sponsors', 'permissions', 'servicePoints', 'preferredServicePoint', 'readingRoomsAccessList']);
const today = moment().endOf('day');
const curActive = user.active;
const prevActive = prevUser.active;
Expand Down
Loading

0 comments on commit 56277f9

Please sign in to comment.