Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UITEN-278 - create reading room from tenant settings #393

Merged
merged 18 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [UITEN-287](https://folio-org.atlassian.net/browse/UITEN-287) Add new permission to create, edit and remove reading room access in tenant settings.
* [UITEN-277](https://issues.folio.org/browse/UITEN-277) Ensure Reading Room Access settings page is wrapped by `Title Manager`.
* [UITEN-276](https://issues.folio.org/browse/UITEN-276) Reading Room Access (settings): Basic Layout.
* [UITEN-278] (https://issues.folio.org/browse/UITEN-278) Reading Room Access (settings): Create new reading room.

## [8.1.0](https://github.com/folio-org/ui-tenant-settings/tree/v8.1.0)(2024-03-19)
[Full Changelog](https://github.com/folio-org/ui-tenant-settings/compare/v8.0.0...v8.1.0)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
"displayName": "Settings (tenant): Can view reading room access",
"subPermissions": [
"reading-room.collection.get",
"inventory-storage.service-points.collection.get",
"settings.tenant-settings.enabled"
],
"visible": true
Expand Down Expand Up @@ -242,8 +243,8 @@
"devDependencies": {
"@babel/core": "^7.20.12",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-class-properties": "^7.12.1",
"@babel/plugin-proposal-decorators": "^7.0.0",
"@babel/plugin-transform-class-properties": "^7.12.1",
"@babel/plugin-transform-private-methods": "^7.18.6",
"@babel/plugin-transform-private-property-in-object": "^7.21.11",
"@babel/plugin-transform-runtime": "^7.10.5",
Expand Down
168 changes: 96 additions & 72 deletions src/settings/ReadingRoomAccess/ReadingRoomAccess.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,18 @@
import React from 'react';
import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import _ from 'lodash';

import { TitleManager, useStripes } from '@folio/stripes/core';
import {
Label,
Checkbox,
} from '@folio/stripes/components';
import { Label } from '@folio/stripes/components';
import { ControlledVocab } from '@folio/stripes/smart-components';

const readingRoomsData = {
values: { records: [
{
'id': 1,
'name': 'RR1',
'public': true,
'servicePoint': [
{
name: 'Circ Desk 1',
id: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f',
},
{
id: 'c4c90014-c8c9-4ade-8f24-b5e313319f4b',
name: 'Circ Desk 2'
},
],
// metadata: {
// 'createdDate': '2024-03-21T10:59:25.085+00:00',
// 'createdByUserId': 'af5ad81e-6857-5b65-9c0c-60942e56f872',
// 'updatedDate': '2024-03-21T10:59:25.085+00:00',
// 'updatedByUserId': 'af5ad81e-6857-5b65-9c0c-60942e56f872'
// }
},
{
'id': 2,
'name': 'RR2',
'public': true,
'servicePoint': [{
name: 'Circ Desk 1',
id: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f',
}],
// metadata: {
// 'createdDate': '2024-03-21T10:59:25.085+00:00',
// 'createdByUserId': 'af5ad81e-6857-5b65-9c0c-60942e56f872',
// 'updatedDate': '2024-03-21T10:59:25.085+00:00',
// 'updatedByUserId': 'af5ad81e-6857-5b65-9c0c-60942e56f872'
// }
},
] },
updaters: {
records: []
},
updaterIds: [],
};
import { readingRoomAccessColumns } from './constant';
import { getFormatter } from './getFormatter';
import { getFieldComponents } from './getFieldComponents';
import { getValidators } from './getValidators';

const hiddenFields = ['numberOfObjects', 'lastUpdated'];
const visibleFields = ['name', 'public', 'servicePoint'];
const formatter = {
'public': (record) => <Checkbox checked={record.public} disabled />,
'servicePoint': (value) => {
const asp = value.servicePoint || [];
const items = asp.map(a => <li key={a.name}>{a.name}</li>);
return <ul className="marginBottom0">{items}</ul>;
}
};
const translations = {
cannotDeleteTermHeader: 'ui-tenant-settings.settings.addresses.cannotDeleteTermHeader',
cannotDeleteTermMessage: 'ui-tenant-settings.settings.addresses.cannotDeleteTermMessage',
Expand All @@ -74,49 +24,123 @@ const translations = {
const ReadingRoomAccess = (props) => {
const intl = useIntl();
const stripes = useStripes();
const { resources } = props;

// service points defined in the tenant
const servicePoints = _.get(resources, ['RRAServicePoints', 'records', 0, 'servicepoints'], []);
/**
* A reading room can have more than one service points assigned to it.
* but a servicepoint cannot be mapped to more than one reading room
*/
const sps = [];
const rrs = _.get(resources, ['values', 'records']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about to handle it with base array methods to avoid this tracking of closures?

Maybe like this:

const sps = rrs.reduce((acc, rr) => {
  acc.push(...(rr.servicePoints || []).map((s) => s.value));

  return [...new Set(acc)];
}, []);

Or maybe

const sps = rrs
  .map((rr) => rr.servicePoints || [])
  .map((s) => s.value)
  .flat();

const uniqSps = [...new Set(spss)];

Note: I didn't check it live with your code, just as an example

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quickly check, but it seems not equivalent. I prefer to retain my implementation.


rrs.forEach(rr => {
const asp = rr.servicePoints || [];
asp.forEach(s => {
if (!sps.includes(s.value)) {
sps.push(s.value);
}
});
});

const options = servicePoints.reduce((acc, s) => {
if (!sps.includes(s.id) || s.name === 'None') {
acc.push({ value: s.id, label: s.name });
}
return acc;
}, []);

const fieldLabels = useMemo(() => ({
[readingRoomAccessColumns.NAME]: intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room-access.name' }),
[readingRoomAccessColumns.ISPUBLIC]: intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room-access.public' }),
[readingRoomAccessColumns.SERVICEPOINTS]: intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room-access.asp' }),
}), [intl]);

const visibleFields = useMemo(() => ([
readingRoomAccessColumns.NAME,
readingRoomAccessColumns.ISPUBLIC,
readingRoomAccessColumns.SERVICEPOINTS,
]), []);

const getRequiredLabel = useCallback(columnLabel => (
<Label required>{columnLabel}</Label>
), []);

const columnMapping = {
name: (
<Label
tagName="span"
required
>
{
intl.formatMessage({ id:'ui-tenant-settings.settings.reading-room-access.name' })
const columnMapping = useMemo(() => ({
[readingRoomAccessColumns.NAME]: getRequiredLabel(fieldLabels[readingRoomAccessColumns.NAME]),
[readingRoomAccessColumns.ISPUBLIC]: fieldLabels[readingRoomAccessColumns.ISPUBLIC],
[readingRoomAccessColumns.SERVICEPOINTS]: getRequiredLabel(fieldLabels[readingRoomAccessColumns.SERVICEPOINTS])
}), [fieldLabels, getRequiredLabel]);

const formatter = useMemo(() => getFormatter({ fieldLabels }), [fieldLabels]);

const validateItem = useCallback((item, items) => {
const errors = Object.values(readingRoomAccessColumns).reduce((acc, field) => {
const error = getValidators(field)?.(item, items);

if (error) {
acc[field] = error;
}
</Label>),
public: intl.formatMessage({ id:'ui-tenant-settings.settings.reading-room-access.public' }),
servicePoint: intl.formatMessage({ id:'ui-tenant-settings.settings.reading-room-access.asp' }),
};

const editable = false; // stripes.hasPerm('ui-users.settings.reading-room-access.all');
return acc;
}, {});

return errors;
}, []);

const validate = (item, index, items) => validateItem(item, items) || {};

const editable = stripes.hasPerm('ui-tenant-settings.settings.reading-room-access.all');

return (
<TitleManager page={intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room.title' })}>
<ControlledVocab
{...props}
id="reading-room-access-settings"
baseUrl="reading-room"
stripes={stripes}
label={intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room-access.label' })}
objectLabel={intl.formatMessage({ id: 'ui-tenant-settings.settings.reading-room-access.label' })}
resources={readingRoomsData}
records="readingRooms"
visibleFields={visibleFields}
columnMapping={columnMapping}
hiddenFields={hiddenFields}
formatter={formatter}
translations={translations}
editable={editable}
fieldComponents={getFieldComponents(fieldLabels, options)}
validate={validate}
actionSuppressor={{ // TODO: action suppressor will be removed in the scope of another ticket
edit: () => true,
delete: () => true,
}}
formType="final-form"
/>
</TitleManager>
);
};

ReadingRoomAccess.manifest = Object.freeze({
values: {
type: 'okapi',
records: 'readingRooms',
path: 'reading-room',
GET: {
path: 'reading-room?query=cql.allRecords=1 sortby name&limit=100'
}
},
updaterIds: [],
RRAServicePoints: {
type: 'okapi',
resource: 'service-points',
path: 'service-points?limit=200',
},
});

ReadingRoomAccess.propTypes = {
resources: PropTypes.object,
mutator: PropTypes.object
};

export default ReadingRoomAccess;
Loading
Loading