diff --git a/CHANGELOG.md b/CHANGELOG.md
index 261199c4..aa6e22fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@
* [UITEN-274](https://folio-org.atlassian.net/browse/UITEN-274) Use Save & close button label stripes-component translation key.
* [UITEN-280](https://folio-org.atlassian.net/browse/UITEN-280) Conditionally include SSO Settings based on login-saml interface.
+* [UITEN-281](https://folio-org.atlassian.net/browse/UITEN-281) Add Routing service point option to Service point page(ECS only).
+* [UITEN-285](https://folio-org.atlassian.net/browse/UITEN-285) Add Confirm Routing service point change modal to edit Service point page(ECS Only).
## [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)
diff --git a/jest.config.js b/jest.config.js
index 98599830..22988ec5 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -19,6 +19,7 @@ module.exports = {
moduleNameMapper: {
'^.+\\.(css)$': 'identity-obj-proxy',
'^.+\\.(svg)$': 'identity-obj-proxy',
+ '^.+\\.(png)$': 'identity-obj-proxy',
'ky': 'ky/umd',
},
testMatch: ['**/(lib|src)/**/?(*.)test.{js,jsx}'],
diff --git a/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.js b/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.js
new file mode 100644
index 00000000..2caf0309
--- /dev/null
+++ b/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.js
@@ -0,0 +1,54 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { FormattedMessage } from 'react-intl';
+import {
+ Button,
+ Modal,
+ ModalFooter,
+} from '@folio/stripes/components';
+
+const ConfirmEcsRequestRoutingChangeModal = ({
+ open,
+ targetValue,
+ onConfirm,
+ onCancel,
+}) => {
+ const footer = (
+
+
+
+
+ );
+
+ return (
+ }
+ open={open}
+ size="small"
+ footer={footer}
+ >
+
+
+ );
+};
+
+ConfirmEcsRequestRoutingChangeModal.propTypes = {
+ open: PropTypes.bool.isRequired,
+ targetValue: PropTypes.bool.isRequired,
+ onConfirm: PropTypes.func.isRequired,
+ onCancel: PropTypes.func.isRequired,
+};
+
+export default ConfirmEcsRequestRoutingChangeModal;
diff --git a/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.test.js b/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.test.js
new file mode 100644
index 00000000..2f33eff5
--- /dev/null
+++ b/src/settings/ServicePoints/ConfirmEcsRequestRoutingChangeModal.test.js
@@ -0,0 +1,102 @@
+import {
+ render,
+ screen,
+ fireEvent,
+} from '@testing-library/react';
+
+import { runAxeTest } from '@folio/stripes-testing';
+
+import ConfirmEcsRequestRoutingChangeModal from './ConfirmEcsRequestRoutingChangeModal';
+
+const defaultProps = {
+ open: true,
+ targetValue: true,
+ onConfirm: jest.fn(),
+ onCancel: jest.fn(),
+};
+const testIds = {
+ confirmButton: 'confirmButton',
+ cancelButton: 'cancelButton',
+};
+const messageIds = {
+ title: 'ui-tenant-settings.settings.confirmEcsRequestRoutingChangeModal.title',
+ messageNoToYes: 'ui-tenant-settings.settings.confirmEcsRequestRoutingChangeModal.messageNoToYes',
+ messageYesToNo: 'ui-tenant-settings.settings.confirmEcsRequestRoutingChangeModal.messageYesToNo',
+ confirmButton: 'ui-tenant-settings.settings.modal.button.confirm',
+ cancelButton: 'ui-tenant-settings.settings.modal.button.cancel',
+};
+
+describe('ConfirmEcsRequestRoutingChangeModal', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render(
+
+ );
+ });
+
+ it('should render with no axe errors', async () => {
+ await runAxeTest({
+ rootNode: document.body,
+ });
+ });
+
+ it('should render title', () => {
+ expect(screen.getByText(messageIds.title)).toBeVisible();
+ });
+
+ it('should render message', () => {
+ expect(screen.getByText(messageIds.messageNoToYes)).toBeVisible();
+ });
+
+ describe('Alternative props', () => {
+ const props = {
+ ...defaultProps,
+ targetValue: false,
+ };
+
+ beforeEach(() => {
+ render(
+
+ );
+ });
+
+ it('should render message', () => {
+ expect(screen.getByText(messageIds.messageYesToNo)).toBeVisible();
+ });
+ });
+
+ describe('Confirm button', () => {
+ it('should render confirm button', () => {
+ expect(screen.getByTestId(testIds.confirmButton)).toBeVisible();
+ });
+
+ it('should render confirm button text', () => {
+ expect(screen.getByText(messageIds.confirmButton)).toBeVisible();
+ });
+
+ it('should call onConfirm', () => {
+ fireEvent.click(screen.getByTestId(testIds.confirmButton));
+
+ expect(defaultProps.onConfirm).toHaveBeenCalled();
+ });
+ });
+
+ describe('Cancel button', () => {
+ it('should render cancel button', () => {
+ expect(screen.getByTestId(testIds.cancelButton)).toBeVisible();
+ });
+
+ it('should render cancel button text', () => {
+ expect(screen.getByText(messageIds.cancelButton)).toBeVisible();
+ });
+
+ it('should call onCancel', () => {
+ fireEvent.click(screen.getByTestId(testIds.cancelButton));
+
+ expect(defaultProps.onCancel).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.js b/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.js
index 258e8698..6c32e96d 100644
--- a/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.js
+++ b/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.js
@@ -20,13 +20,13 @@ const ConfirmPickupLocationChangeModal = ({
autoFocus
onClick={onConfirm}
>
-
+
);
diff --git a/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.test.js b/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.test.js
index 93865153..5e696d3e 100644
--- a/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.test.js
+++ b/src/settings/ServicePoints/ConfirmPickupLocationChangeModal.test.js
@@ -22,8 +22,8 @@ const testIds = {
const messageIds = {
title: 'ui-tenant-settings.settings.confirmPickupLocationChangeModal.title',
message: 'ui-tenant-settings.settings.confirmPickupLocationChangeModal.message',
- buttonConfirm: 'ui-tenant-settings.settings.confirmPickupLocationChangeModal.button.confirm',
- buttonCancel: 'ui-tenant-settings.settings.confirmPickupLocationChangeModal.button.cancel',
+ buttonConfirm: 'ui-tenant-settings.settings.modal.button.confirm',
+ buttonCancel: 'ui-tenant-settings.settings.modal.button.cancel',
};
describe('ConfirmPickupLocationChangeModal', () => {
diff --git a/src/settings/ServicePoints/ServicePointDetail.js b/src/settings/ServicePoints/ServicePointDetail.js
index 0443d6d3..0b35ecf7 100644
--- a/src/settings/ServicePoints/ServicePointDetail.js
+++ b/src/settings/ServicePoints/ServicePointDetail.js
@@ -1,16 +1,18 @@
-import { cloneDeep, keyBy, orderBy } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import {
injectIntl,
FormattedMessage,
} from 'react-intl';
+import { cloneDeep, keyBy, orderBy } from 'lodash';
+
import { Accordion, Col, ExpandAllButton, KeyValue, Row } from '@folio/stripes/components';
import { ViewMetaData } from '@folio/stripes/smart-components';
-
import { TitleManager } from '@folio/stripes/core';
+
import LocationList from './LocationList';
import StaffSlipList from './StaffSlipList';
+import { isEcsRequestRoutingVisible, isEcsRequestRoutingAssociatedFieldsVisible } from './utils';
import { intervalPeriods } from '../../constants';
import { closedLibraryDateManagementMapping } from './constants';
@@ -19,6 +21,7 @@ class ServicePointDetail extends React.Component {
intl: PropTypes.object,
stripes: PropTypes.shape({
connect: PropTypes.func.isRequired,
+ hasInterface: PropTypes.func.isRequired,
}).isRequired,
initialValues: PropTypes.object,
parentResources: PropTypes.object,
@@ -80,7 +83,7 @@ class ServicePointDetail extends React.Component {
}
render() {
- const { initialValues, parentResources } = this.props;
+ const { initialValues, parentResources, stripes } = this.props;
const locations = (parentResources.locations || {}).records || [];
const staffSlips = orderBy((parentResources.staffSlips || {}).records || [], 'name');
const servicePoint = initialValues;
@@ -133,56 +136,74 @@ class ServicePointDetail extends React.Component {
/>
-
-
- }
- value={servicePoint.shelvingLagTime}
- />
-
-
-
-
- }>
- { servicePoint.pickupLocation
- ?
- :
- }
-
-
-
- { servicePoint.pickupLocation && (
+ {isEcsRequestRoutingVisible(stripes) && (
+
+
+ }>
+ { servicePoint.ecsRequestRouting
+ ?
+ :
+ }
+
+
+
+ )}
+ {isEcsRequestRoutingAssociatedFieldsVisible(stripes, servicePoint.ecsRequestRouting) && (
<>
-
+
}
- value={`${duration} ${this.intervalPeriodMap[intervalId].label}`}
+ label={}
+ value={servicePoint.shelvingLagTime}
/>
-
- }>
-
+
+ }>
+ { servicePoint.pickupLocation
+ ?
+ :
+ }
+ { servicePoint.pickupLocation && (
+ <>
+
+
+ }
+ value={`${duration} ${this.intervalPeriodMap[intervalId].label}`}
+ />
+
+
+
+
+ }>
+
+
+
+
+ >
+ )
+ }
+
>
- )
- }
-
+ )}
-
+ {isEcsRequestRoutingAssociatedFieldsVisible(stripes, servicePoint.ecsRequestRouting) && (
+
+ )}
);
diff --git a/src/settings/ServicePoints/ServicePointForm.js b/src/settings/ServicePoints/ServicePointForm.js
index 1e0c0e3a..9ce2af6c 100644
--- a/src/settings/ServicePoints/ServicePointForm.js
+++ b/src/settings/ServicePoints/ServicePointForm.js
@@ -30,6 +30,7 @@ import { ViewMetaData } from '@folio/stripes/smart-components';
import stripesFinalForm from '@folio/stripes/final-form';
import { useStripes } from '@folio/stripes/core';
+import ConfirmEcsRequestRoutingChangeModal from './ConfirmEcsRequestRoutingChangeModal';
import ConfirmPickupLocationChangeModal from './ConfirmPickupLocationChangeModal';
import Period from '../../components/Period';
import LocationList from './LocationList';
@@ -39,6 +40,8 @@ import { intervalPeriods } from '../../constants';
import {
validateServicePointForm,
getUniquenessValidation,
+ isEcsRequestRoutingVisible,
+ isEcsRequestRoutingAssociatedFieldsVisible,
} from './utils';
import {
@@ -49,9 +52,13 @@ import {
import styles from './ServicePoints.css';
+export const SELECTED_ROUTING_SERVICE_POINT_VALUE = 'true';
export const SELECTED_PICKUP_LOCATION_VALUE = 'true';
export const UNSELECTED_PICKUP_LOCATION_VALUE = 'false';
export const LAYER_EDIT = 'layer=edit';
+export const isConfirmEcsRequestRoutingChangeModalShouldBeVisible = (search, stripes) => (
+ search.includes(LAYER_EDIT) && isEcsRequestRoutingVisible(stripes)
+);
export const isConfirmPickupLocationChangeModalShouldBeVisible = (search, value) => (
search.includes(LAYER_EDIT) && value === UNSELECTED_PICKUP_LOCATION_VALUE
);
@@ -73,6 +80,8 @@ const ServicePointForm = ({
generalSection: true,
locationSection: true
});
+ const [ecsRequestRoutingTargetValue, setEcsRequestRoutingTargetValue] = useState(false);
+ const [isConfirmEcsRequestRoutingChangeModal, setIsConfirmEcsRequestRoutingChangeModal] = useState(false);
const [isConfirmPickupLocationChangeModal, setIsConfirmPickupLocationChangeModal] = useState(false);
const stripes = useStripes();
const intl = useIntl();
@@ -88,11 +97,11 @@ const ServicePointForm = ({
const selectOptions = [
{
- label: intl.formatMessage({ id: 'ui-tenant-settings.settings.servicePoints.pickupLocation.no' }),
+ label: intl.formatMessage({ id: 'ui-tenant-settings.settings.servicePoints.value.no' }),
value: false
},
{
- label: intl.formatMessage({ id: 'ui-tenant-settings.settings.servicePoints.pickupLocation.yes' }),
+ label: intl.formatMessage({ id: 'ui-tenant-settings.settings.servicePoints.value.yes' }),
value: true
}
];
@@ -103,6 +112,12 @@ const ServicePointForm = ({
}
));
+ const onConfirmConfirmEcsRequestRoutingChangeModal = () => {
+ form.change('ecsRequestRouting', ecsRequestRoutingTargetValue);
+ setIsConfirmEcsRequestRoutingChangeModal(false);
+ };
+ const onCancelConfirmEcsRequestRoutingChangeModal = () => setIsConfirmEcsRequestRoutingChangeModal(false);
+
const onConfirmConfirmPickupLocationChangeModal = () => {
form.change('pickupLocation', false);
setIsConfirmPickupLocationChangeModal(false);
@@ -200,6 +215,17 @@ const ServicePointForm = ({
)));
};
+ const handleEcsRequestRoutingChange = (e) => {
+ const value = e.target.value;
+
+ if (isConfirmEcsRequestRoutingChangeModalShouldBeVisible(search, stripes)) {
+ setEcsRequestRoutingTargetValue(value === SELECTED_ROUTING_SERVICE_POINT_VALUE);
+ setIsConfirmEcsRequestRoutingChangeModal(true);
+ } else {
+ form.change('ecsRequestRouting', value === SELECTED_ROUTING_SERVICE_POINT_VALUE);
+ }
+ };
+
const handleChange = (e) => {
const value = e.target.value;
@@ -290,67 +316,96 @@ const ServicePointForm = ({
/>
-
-
- }
- name="shelvingLagTime"
- id="input-service-shelvingLagTime"
- component={TextField}
- fullWidth
- disabled={disabled}
- />
-
-
-
-
- }
- name="pickupLocation"
- id="input-service-pickupLocation"
- component={Select}
- dataOptions={selectOptions}
- onChange={handleChange}
- disabled={disabled}
- />
-
-
- {
- formValues.pickupLocation && (
- <>
-
-
+
+ }
+ name="ecsRequestRouting"
+ id="input-service-ecsRequestRouting"
+ component={Select}
+ dataOptions={selectOptions}
+ onChange={handleEcsRequestRoutingChange}
+ disabled={disabled}
+ />
+
+
+ )}
+ {isEcsRequestRoutingAssociatedFieldsVisible(stripes, formValues.ecsRequestRouting) && (
+ <>
+
+
+ }
+ name="shelvingLagTime"
+ id="input-service-shelvingLagTime"
+ component={TextField}
+ fullWidth
+ disabled={disabled}
/>
-
-
+
+
+
+
}
- name="holdShelfClosedLibraryDateManagement"
+ data-test-pickup-location
+ label={}
+ name="pickupLocation"
+ id="input-service-pickupLocation"
component={Select}
- dataOptions={getClosedLibraryDateManagementOptions()}
+ dataOptions={selectOptions}
+ onChange={handleChange}
+ disabled={disabled}
/>
-
- >
- )
- }
-
+
+
+ {
+ formValues.pickupLocation && (
+ <>
+
+
+ }
+ name="holdShelfClosedLibraryDateManagement"
+ component={Select}
+ dataOptions={getClosedLibraryDateManagementOptions()}
+ />
+
+ >
+ )
+ }
+
+ >
+ )}
-
+ {isEcsRequestRoutingAssociatedFieldsVisible(stripes, formValues.ecsRequestRouting) && (
+
+ )}
+ {isConfirmEcsRequestRoutingChangeModalShouldBeVisible(search, stripes) && (
+
+ )}
-
{
userEvent.selectOptions(screen.getByRole('combobox', { name: /settings.servicePoints.pickupLocation/ }), 'true');
- expect(screen.getByRole('option', { name: /settings.servicePoints.pickupLocation.yes/ }).selected).toBe(true);
+ expect(screen.getAllByRole('option', { name: /settings.servicePoints.value.yes/ })[1].selected).toBe(true);
});
describe('when pick location is yes', () => {
@@ -97,7 +97,7 @@ describe('ServicePointFormContainer', () => {
describe('when hold shelf expiry interval id is short term period Days', () => {
beforeEach(() => {
- userEvent.selectOptions(screen.getAllByRole('combobox')[1], 'Days');
+ userEvent.selectOptions(screen.getAllByRole('combobox')[2], 'Days');
});
it('should render ServicePointFormContainer closed library date management select with changed options ', () => {
diff --git a/src/settings/ServicePoints/utils.js b/src/settings/ServicePoints/utils.js
index 9df81086..af581fae 100644
--- a/src/settings/ServicePoints/utils.js
+++ b/src/settings/ServicePoints/utils.js
@@ -53,3 +53,11 @@ export const getUniquenessValidation = (field, mutator) => {
});
};
};
+
+export const isEcsRequestRoutingVisible = (stripes) => (
+ stripes.hasInterface('consortia') && stripes.hasInterface('ecs-tlr')
+);
+
+export const isEcsRequestRoutingAssociatedFieldsVisible = (stripes, ecsRequestRouting) => (
+ (isEcsRequestRoutingVisible(stripes) && !ecsRequestRouting) || !isEcsRequestRoutingVisible(stripes)
+);
diff --git a/src/settings/ServicePoints/utils.test.js b/src/settings/ServicePoints/utils.test.js
new file mode 100644
index 00000000..6458327f
--- /dev/null
+++ b/src/settings/ServicePoints/utils.test.js
@@ -0,0 +1,65 @@
+import {
+ isEcsRequestRoutingVisible,
+} from './utils';
+
+describe('isEcsRequestRoutingVisible', () => {
+ it('should return true when both interfaces present', () => {
+ const stripes = {
+ hasInterface: (currentInterface) => {
+ const interfaces = {
+ consortia: true,
+ 'ecs-tlr': true,
+ };
+
+ return interfaces[currentInterface];
+ },
+ };
+
+ expect(isEcsRequestRoutingVisible(stripes)).toBe(true);
+ });
+
+ it('should return false when one interfaces absent', () => {
+ const stripes = {
+ hasInterface: (currentInterface) => {
+ const interfaces = {
+ consortia: true,
+ 'ecs-tlr': false,
+ };
+
+ return interfaces[currentInterface];
+ },
+ };
+
+ expect(isEcsRequestRoutingVisible(stripes)).toBe(false);
+ });
+
+ it('should return false when one interfaces absent', () => {
+ const stripes = {
+ hasInterface: (currentInterface) => {
+ const interfaces = {
+ consortia: false,
+ 'ecs-tlr': true,
+ };
+
+ return interfaces[currentInterface];
+ },
+ };
+
+ expect(isEcsRequestRoutingVisible(stripes)).toBe(false);
+ });
+
+ it('should return false when both interfaces absent', () => {
+ const stripes = {
+ hasInterface: (currentInterface) => {
+ const interfaces = {
+ consortia: false,
+ 'ecs-tlr': false,
+ };
+
+ return interfaces[currentInterface];
+ },
+ };
+
+ expect(isEcsRequestRoutingVisible(stripes)).toBe(false);
+ });
+});
diff --git a/translations/ui-tenant-settings/en.json b/translations/ui-tenant-settings/en.json
index 85f35932..3f9fe78d 100644
--- a/translations/ui-tenant-settings/en.json
+++ b/translations/ui-tenant-settings/en.json
@@ -138,6 +138,7 @@
"settings.servicePoints.code": "Code",
"settings.servicePoints.discoveryDisplayName": "Discovery display name",
"settings.servicePoints.description": "Description",
+ "settings.servicePoints.ecsRequestRouting": "Routing service point",
"settings.servicePoints.shelvingLagTime": "Shelving lag time (minutes)",
"settings.servicePoints.pickupLocation": "Pickup location",
"settings.servicePoints.feeFineOwner": "Fee fine owner",
@@ -163,8 +164,8 @@
"settings.servicePoints.validation.numeric": "Please enter a number to continue",
"settings.servicePoints.validation.name.unique": "Service point name must be unique",
"settings.servicePoints.validation.code.unique": "Code must be unique",
- "settings.servicePoints.pickupLocation.yes": "Yes",
- "settings.servicePoints.pickupLocation.no": "No",
+ "settings.servicePoints.value.yes": "Yes",
+ "settings.servicePoints.value.no": "No",
"settings.intervalPeriod.minutes": "Minutes",
"settings.intervalPeriod.hours": "Hours",
"settings.intervalPeriod.days": "Days",
@@ -216,8 +217,11 @@
"permission.settings.servicepoints.view": "Settings (tenant): Can view service points",
"permission.settings.bursar-exports": "Settings (tenant): Bursar admin",
+ "settings.confirmEcsRequestRoutingChangeModal.title": "Confirm Routing service point change",
+ "settings.confirmEcsRequestRoutingChangeModal.messageYesToNo": "Changing this Routing service point from \"Yes\" to \"No\" will remove it from existing Request policies and affect all Circulation rules using the policies.",
+ "settings.confirmEcsRequestRoutingChangeModal.messageNoToYes": "Changing Routing service point from \"No\" to \"Yes\" will remove the Service point from being a Pickup location in existing Request policies and affect all Circulation rules using the policies.",
"settings.confirmPickupLocationChangeModal.title": "Confirm Pickup location change",
"settings.confirmPickupLocationChangeModal.message": "Changing this Pickup location from \"Yes\" to \"No\" will remove it from existing Request policies and affect all Circulation rules using the policies.",
- "settings.confirmPickupLocationChangeModal.button.confirm": "Confirm",
- "settings.confirmPickupLocationChangeModal.button.cancel": "Back"
+ "settings.modal.button.confirm": "Confirm",
+ "settings.modal.button.cancel": "Back"
}