From 56277f94999d7fa09504f2fd5e11835025b54013 Mon Sep 17 00:00:00 2001 From: Priyanka Terala Date: Tue, 21 May 2024 20:51:00 +0530 Subject: [PATCH 01/11] UIU-3115 - reading room acecss acoordion on user edit view --- CHANGELOG.md | 1 + .../EditReadingRoomAccess.js | 67 ++++++++++ .../EditReadingRoomAccess.test.js | 116 ++++++++++++++++++ .../EditReadingRoomAccess/constants.js | 17 +++ .../EditReadingRoomAccess/getFormatter.js | 69 +++++++++++ .../EditReadingRoomAccess/index.js | 1 + src/components/EditSections/index.js | 1 + src/routes/UserRecordContainer.js | 9 ++ src/views/UserEdit/UserEdit.js | 22 +++- src/views/UserEdit/UserEdit.test.js | 29 +++++ src/views/UserEdit/UserForm.js | 14 +++ src/views/UserEdit/UserForm.test.js | 1 + translations/ui-users/en.json | 8 ++ 13 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.js create mode 100644 src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.test.js create mode 100644 src/components/EditSections/EditReadingRoomAccess/constants.js create mode 100644 src/components/EditSections/EditReadingRoomAccess/getFormatter.js create mode 100644 src/components/EditSections/EditReadingRoomAccess/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e3d90e85..22049eeff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.js b/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.js new file mode 100644 index 000000000..b37593b11 --- /dev/null +++ b/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.js @@ -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]: , + [rraColumns.READING_ROOM_NAME]: , + [rraColumns.NOTES]: , + }; + 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 ( + } + displayWhenClosed={formData.length} + > + + + ); +}; + +EditReadingRoomAccess.propTypes = { + expanded: PropTypes.bool, + onToggle: PropTypes.func, + accordionId: PropTypes.string.isRequired, + formData: PropTypes.object, + form: PropTypes.object, +}; + +export default EditReadingRoomAccess; diff --git a/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.test.js b/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.test.js new file mode 100644 index 000000000..86c20742e --- /dev/null +++ b/src/components/EditSections/EditReadingRoomAccess/EditReadingRoomAccess.test.js @@ -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 = () => ( + <> + + + ); + renderWithRouter( +
+ ); +}; + +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()); + }); +}); diff --git a/src/components/EditSections/EditReadingRoomAccess/constants.js b/src/components/EditSections/EditReadingRoomAccess/constants.js new file mode 100644 index 000000000..febf8559d --- /dev/null +++ b/src/components/EditSections/EditReadingRoomAccess/constants.js @@ -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' + } +]; diff --git a/src/components/EditSections/EditReadingRoomAccess/getFormatter.js b/src/components/EditSections/EditReadingRoomAccess/getFormatter.js new file mode 100644 index 000000000..cad8cc300 --- /dev/null +++ b/src/components/EditSections/EditReadingRoomAccess/getFormatter.js @@ -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 }) => ( + { + return ( + { + updateRecord(record, val, input.name, rowIndex); + }} + /> + ); + }} + /> + ), + { rowIndex: PropTypes.number, record: PropTypes.object } + ), + [rraColumns.READING_ROOM_NAME] : ({ readingRoomName }) => readingRoomName, + [rraColumns.NOTES] : Object.assign( + ({ rowIndex, ...record }) => ( + ( +