Skip to content

Commit

Permalink
UIU-3112 - Implement sort and filter functionality on reading room ac…
Browse files Browse the repository at this point in the history
…cess MCL (#2691)

* UIU-3114 - integrate APIs for RRA on user record detail

* UIU-3114 - add unit test

* UIU-3114 - add unit test

* UIU-3114-add permission checks

* UIU-3114 - refine code

* UIU-3114 - refine and cleanup

* UIU-3114 - Prevent fetching user's reading room permissions in case of new user creation

* UIU-3114 - Add EOF

* UIU-3112 - Implement sort and filter functionality on reading room access MCL

* UIU-3112 - add unit test

* UIU-3112 - add unit test

* UIU-3112 - refine, fix comments

* UIU-3112 - refine - address comments

* UIU-3112 - fix failed test
  • Loading branch information
Terala-Priyanka authored May 20, 2024
1 parent b2b426f commit b09e01e
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, useIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { get } from 'lodash';
import { get, orderBy, noop } from 'lodash';

import {
Accordion,
Expand All @@ -11,9 +11,11 @@ import {
Headline,
MultiColumnList,
SearchField,
Icon,
} from '@folio/stripes/components';

import { rraColumns } from './constant';
import { rraColumns, DEFAULT_SORT_ORDER } from './constant';
import { sortTypes } from '../../../constants';
import { getFormatter } from './getFormatter';
import css from './ReadingRoomAccess.css';

Expand All @@ -22,19 +24,55 @@ const ReadingRoomAccess = (props) => {
accordionId,
expanded,
onToggle,
userRRAPermissions,
readingRoomPermissions,
} = props;
const intl = useIntl();
const [filteredRRA, setFilteredRRA] = useState([]);
const userRRAPermissions = useMemo(() => readingRoomPermissions?.records, [readingRoomPermissions]);
const { isPending } = readingRoomPermissions;
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" />,
[rraColumns.ID]: <FormattedMessage id="ui-users.readingRoom.lastUpdated" />,
};
const visibleColumns = Object.keys(columnMapping);
const sortInitialState = {
data: [],
order: DEFAULT_SORT_ORDER,
direction: sortTypes.ASC,
};
const [sortedRecordsDetails, setSortedRecordsDetails] = useState(sortInitialState);

useEffect(() => {
setFilteredRRA(userRRAPermissions);
}, [userRRAPermissions]);
if (!isPending) {
setSortedRecordsDetails(prev => ({
...prev,
data: orderBy(userRRAPermissions, prev.order, prev.direction)
}));
}
}, [userRRAPermissions, isPending]);

const filterReadingRoomsByName = (e) => {
const name = e.target.value;
const filteredRRs = userRRAPermissions.filter(r => r.readingRoomName.includes(name));
setFilteredRRA(filteredRRs);
setSortedRecordsDetails(prev => ({
...prev,
data: orderBy(filteredRRs, prev.order, prev.direction)
}));
};

const onSort = (e, meta) => {
let newSortDirection = sortTypes.ASC;
if (sortedRecordsDetails.order === meta.name) {
newSortDirection = sortedRecordsDetails.direction === sortTypes.ASC ? sortTypes.DESC : sortTypes.ASC;
}
const sortedData = orderBy(sortedRecordsDetails.data, [meta.name], newSortDirection);

setSortedRecordsDetails({
data: sortedData,
order: meta.name,
direction: newSortDirection
});
};

const renderName = (usr) => {
Expand Down Expand Up @@ -66,35 +104,22 @@ const ReadingRoomAccess = (props) => {
);
};

const visibleColumns = [
rraColumns.ACCESS,
rraColumns.READING_ROOM_NAME,
rraColumns.NOTES,
rraColumns.ID
];
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" />,
[rraColumns.ID]: <FormattedMessage id="ui-users.readingRoom.lastUpdated" />,
};

return (
<Accordion
id={accordionId}
label={<Headline size="large" tag="h3"><FormattedMessage id="ui-users.readingRoom.readingRoomAccess" /></Headline>}
onToggle={onToggle}
open={expanded}
displayWhenClosed={
<Badge>{filteredRRA.length}</Badge>
isPending ? <Icon icon="spinner-ellipsis" /> : <Badge>{userRRAPermissions.length}</Badge>
}
displayWhenOpen={
<div
className={css.rraSearchFieldContainer}
>
<SearchField
onChange={filterReadingRoomsByName}
onClear={() => setFilteredRRA(userRRAPermissions)}
onClear={noop}
placeholder={intl.formatMessage({ id:'ui-users.readingRoom.filter' })}
/>
</div>
Expand All @@ -103,10 +128,14 @@ const ReadingRoomAccess = (props) => {
<MultiColumnList
striped
data-testid="reading-room-access-mcl"
contentData={filteredRRA}
contentData={sortedRecordsDetails.data}
columnMapping={columnMapping}
visibleColumns={visibleColumns}
formatter={getFormatter(lastUpdatedDetails)}
sortOrder={sortedRecordsDetails.order}
sortDirection={`${sortedRecordsDetails.direction}ending`}
onHeaderClick={onSort}
sortedColumn={sortedRecordsDetails.order}
/>
</Accordion>
);
Expand All @@ -116,7 +145,10 @@ ReadingRoomAccess.propTypes = {
expanded: PropTypes.bool,
onToggle: PropTypes.func,
accordionId: PropTypes.string.isRequired,
userRRAPermissions: PropTypes.arrayOf(PropTypes.object),
readingRoomPermissions: PropTypes.shape({
isPending: PropTypes.bool,
records: PropTypes.arrayOf(PropTypes.object),
})
};

export default ReadingRoomAccess;
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const mockedRRAData = [
{
'userId': '2205005b-ca51-4a04-87fd-938eefa8f6de',
'readingRoomId': '0e589a51-5f28-4b59-b923-b036cf56a41d',
'readingRoomName': 'reading room1',
'readingRoomName': 'reading room 2',
'access': 'NOT_ALLOWED'
},
{
Expand All @@ -57,7 +57,10 @@ const props = {
accordionId: 'readingRoomSection',
expanded: false,
onToggle: jest.fn(),
userRRAPermissions: mockedRRAData,
readingRoomPermissions: {
records: mockedRRAData,
isPending: false,
}
};

describe('ReadingRoomAccess', () => {
Expand All @@ -84,13 +87,40 @@ describe('ReadingRoomAccess', () => {
it('should filter MCL records "Name" column, based on the string entered in search box', async () => {
render(<ReadingRoomAccess {...alteredProps} />);
const inputEl = screen.getByPlaceholderText('ui-users.readingRoom.filter');
fireEvent.change(inputEl, { target: { value: 'room1' } });
fireEvent.change(inputEl, { target: { value: 'room 1' } });
const numOfRows = document.querySelectorAll('[class^="mclRowFormatterContainer"]').length;
await waitFor(() => expect(numOfRows).toBe(1));
});

it('should render all records when search string is cleared', async () => {
render(<ReadingRoomAccess {...alteredProps} />);
const inputEl = screen.getByPlaceholderText('ui-users.readingRoom.filter');
fireEvent.change(inputEl, { target: { value: 'room 1' } });
const numOfRows = document.querySelectorAll('[class^="mclRowFormatterContainer"]').length;
await waitFor(() => expect(numOfRows).toBe(1));
fireEvent.change(inputEl, { target: { value: '' } });
expect(document.querySelectorAll('[class^="mclRowFormatterContainer"]').length).toBe(2);
});

it('should render updated date', () => {
render(<ReadingRoomAccess {...alteredProps} />);
expect(screen.getByText('ui-users.readingRoom.metaSection.lastUpdatedDetails')).toBeDefined();
});

it('should sort the records by access, by default', () => {
render(<ReadingRoomAccess {...alteredProps} />);
expect(document.querySelectorAll('[class^="mclCell"]')[0].innerHTML).toBe('Allowed');
});

it('should sort records in descending order of access when access header is clicked', () => {
render(<ReadingRoomAccess {...alteredProps} />);
fireEvent.click(document.getElementById('clickable-list-column-access'));
expect(document.querySelectorAll('[class^="mclCell"]')[0].innerHTML).toBe('Not allowed');
});

it('should sort the records by room name when name column header is clicked', () => {
render(<ReadingRoomAccess {...alteredProps} />);
fireEvent.click(document.getElementById('clickable-list-column-readingroomname'));
expect(document.querySelectorAll('[class^="mclCell"]')[1].innerHTML).toBe('reading room 1');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export const rraColumns = {
NOTES: 'notes',
ID: 'id'
};

export const DEFAULT_SORT_ORDER = rraColumns.ACCESS;
4 changes: 2 additions & 2 deletions src/views/UserDetail/UserDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ class UserDetail extends React.Component {
const isPatronUser = user?.type === USER_TYPES.PATRON;
const isStaffUser = user?.type === USER_TYPES.STAFF;
const displayReadingRoomAccessAccordion = isPatronUser || isStaffUser;
const userRRAPermissions = resources?.userReadingRoomPermissions?.records || [];
const readingRoomPermissions = resources?.userReadingRoomPermissions;

if (this.userNotFound()) {
return (
Expand Down Expand Up @@ -783,7 +783,7 @@ class UserDetail extends React.Component {
accordionId="readingRoomAccessSection"
onToggle={this.handleSectionToggle}
expanded={sections.readingRoomAccessSection}
userRRAPermissions={userRRAPermissions}
readingRoomPermissions={readingRoomPermissions}
/>
</IfPermission>
)
Expand Down
2 changes: 1 addition & 1 deletion translations/ui-users/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@
"readingRoom.name": "Name",
"readingRoom.note": "Note",
"readingRoom.lastUpdated": "Last updated",
"readingRoom.filter": "Filter",
"readingRoom.filter": "Room name",
"readingRoom.allowed": "Allowed",
"readingRoom.notAllowed": "Not allowed",
"readingRoom.metaSection.lastUpdatedDetails": "{date} by {name}",
Expand Down

0 comments on commit b09e01e

Please sign in to comment.