diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05fb70c8..b1536630 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@
* Add optional column "Retrieval service point" to requests search list. Refs UIREQ-1188.
* Increase code coverage for src/ChooseRequestTypeDialog.js by Jest/RTL tests. Refs UIREQ-1044.
* Cleanup retrieval service point implementation from deprecated folder. Refs UIREQ-1211.
+* Increase code coverage for src/ViewRequest.js by Jest/RTL tests. Refs UIREQ-1046.
+* React v19: refactor away from default props for functional components. Refs UIREQ-1101.
+* Add "Retrieval service point" filter. Refs UIREQ-1190.
* Include `Retrieval service point` column in csv exports. Refs UIREQ-1191.
## [11.0.2] (https://github.com/folio-org/ui-requests/tree/v11.0.2) (2024-12-10)
diff --git a/package.json b/package.json
index a8cb21f3..8aee6514 100644
--- a/package.json
+++ b/package.json
@@ -197,6 +197,7 @@
"inflected": "^2.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-query": "^3.39.0",
"react-intl": "^6.4.4",
"react-router-dom": "^5.2.0",
"regenerator-runtime": "^0.13.9"
@@ -220,6 +221,7 @@
"@folio/stripes": "^9.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-query": "^3.39.0",
"react-intl": "^6.4.4",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0"
diff --git a/src/ItemsDialog.js b/src/ItemsDialog.js
index 1dd77754..1ffd64c6 100644
--- a/src/ItemsDialog.js
+++ b/src/ItemsDialog.js
@@ -79,7 +79,7 @@ const ItemsDialog = ({
onRowClick = noop,
mutator,
skippedItemId,
- title,
+ title = '',
instanceId,
}) => {
const [areItemsBeingLoaded, setAreItemsBeingLoaded] = useState(false);
@@ -233,10 +233,6 @@ ItemsDialog.manifest = {
},
};
-ItemsDialog.defaultProps = {
- title: '',
-};
-
ItemsDialog.propTypes = {
open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
diff --git a/src/ViewRequest.test.js b/src/ViewRequest.test.js
index 297d99bd..402e2fa1 100644
--- a/src/ViewRequest.test.js
+++ b/src/ViewRequest.test.js
@@ -1,13 +1,17 @@
-import moment from 'moment-timezone';
+import React from 'react';
import {
render,
screen,
+ waitFor,
} from '@folio/jest-config-stripes/testing-library/react';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
import {
CommandList,
defaultKeyboardShortcuts,
+ Icon,
+ PaneHeaderIconButton,
} from '@folio/stripes/components';
import ViewRequest, {
@@ -15,25 +19,117 @@ import ViewRequest, {
shouldHideMoveAndDuplicate,
} from './ViewRequest';
import RequestForm from './RequestForm';
+import MoveRequestManager from './MoveRequestManager';
+import CancelRequestDialog from './CancelRequestDialog';
+import UserDetail from './UserDetail';
+import ItemDetail from './ItemDetail';
import {
INVALID_REQUEST_HARDCODED_ID,
requestStatuses,
REQUEST_LEVEL_TYPES,
DCB_INSTANCE_ID,
DCB_HOLDINGS_RECORD_ID,
+ REQUEST_LAYERS,
+ fulfillmentTypeMap,
} from './constants';
+import {
+ isProxyFunctionalityAvailable,
+ toUserAddress,
+} from './utils';
import {
duplicateRecordShortcut,
editRecordShortcut,
} from '../test/jest/helpers/shortcuts';
+const testIds = {
+ requestForm: 'requestForm',
+ moveRequestManager: 'moveRequestManager',
+ cancelRequestButton: 'cancelRequestButton',
+ saveRequestButton: 'saveRequestButton',
+ moveRequestButton: 'moveRequestButton',
+ cancelMoveButton: 'cancelMoveButton',
+};
+const updatedRecordRequester = {
+ requester: {
+ personal: {
+ firstName: 'firstName',
+ },
+ },
+};
+const requestQueueUrl = 'requestQueueUrl/';
+
jest.mock('./RequestForm', () => jest.fn(() => null));
-jest.mock('./MoveRequestManager', () => jest.fn(() => null));
+jest.mock('./MoveRequestManager', () => jest.fn(({
+ onMove,
+ onCancelMove,
+}) => {
+ return (
+
+
+
+
+ );
+}));
jest.mock('./ItemDetail', () => jest.fn(() => null));
jest.mock('./UserDetail', () => jest.fn(() => null));
jest.mock('./CancelRequestDialog', () => jest.fn(() => null));
jest.mock('./PositionLink', () => jest.fn(() => null));
jest.mock('./components/TitleInformation', () => jest.fn(() => null));
+jest.mock('./RequestFormContainer', () => jest.fn(({
+ onSubmit,
+ onCancelRequest,
+}) => {
+ const handleSubmit = () => {
+ onSubmit(updatedRecordRequester);
+ };
+ const cancelRequest = () => {
+ onCancelRequest({});
+ };
+
+ return (
+ <>
+
+ >
+ );
+}));
+jest.mock('./utils', () => ({
+ ...jest.requireActual('./utils'),
+ toUserAddress: jest.fn(),
+ isProxyFunctionalityAvailable: jest.fn(() => true),
+}));
+jest.mock('./routes/urls', () => ({
+ requestQueueView: jest.fn(() => requestQueueUrl),
+}));
describe('ViewRequest', () => {
const labelIds = {
@@ -43,6 +139,10 @@ describe('ViewRequest', () => {
moveRequest: 'ui-requests.actions.moveRequest',
reorderQueue: 'ui-requests.actions.reorderQueue',
requestDetailTitle: 'ui-requests.request.detail.title',
+ showTags: 'ui-requests.showTags',
+ noItemInformation: 'ui-requests.item.noInformation',
+ cancellationReason: 'ui-requests.cancellationReason',
+ cancellationAdditionalInformation: 'ui-requests.cancellationAdditionalInformation',
};
const mockedRequest = {
instance: {
@@ -59,6 +159,13 @@ describe('ViewRequest', () => {
metadata: {
createdDate: 'createdDate',
},
+ requester: {
+ id: 'requesterId',
+ },
+ proxy: {
+ id: 'proxyUserId',
+ },
+ proxyUserId: 'proxyUserId',
};
const mockedRequestWithDCBUser = {
...mockedRequest,
@@ -99,10 +206,22 @@ describe('ViewRequest', () => {
onClose: jest.fn(),
onCloseEdit: jest.fn(),
buildRecordsForHoldsShelfReport: jest.fn(),
+ patronGroups: [
+ {
+ id: 'groupId',
+ name: 'groupName',
+ }
+ ],
optionLists: {
cancellationReasons: [
- { id: '1' },
- { id: '2' },
+ {
+ id: 'id_1',
+ name: 'name_1',
+ },
+ {
+ id: 'id_2',
+ name: 'name_2',
+ },
],
servicePoints: [
{ id: 'servicePoint' },
@@ -134,6 +253,13 @@ describe('ViewRequest', () => {
},
isEcsTlrSettingEnabled: false,
isEcsTlrSettingReceived: true,
+ onDuplicate: jest.fn(),
+ onEdit: jest.fn(),
+ };
+ const openRequest = {
+ ...mockedRequest,
+ fulfillmentPreference: fulfillmentTypeMap.HOLD_SHELF,
+ status: requestStatuses.NOT_YET_FILLED,
};
const defaultDCBLendingProps = {
...defaultProps,
@@ -176,26 +302,6 @@ describe('ViewRequest', () => {
expect(screen.getByText(labelIds.requestDetailTitle)).toBeInTheDocument();
});
- describe('when work with request editing', () => {
- beforeAll(() => {
- mockedLocation.search = '?layer=edit';
- });
-
- it('should set "createTitleLevelRequest" to false when try to edit existed request', () => {
- const expectedResult = {
- initialValues : {
- requestExpirationDate: null,
- holdShelfExpirationDate: mockedRequest.holdShelfExpirationDate,
- holdShelfExpirationTime: moment(mockedRequest.holdShelfExpirationDate).format('HH:mm'),
- createTitleLevelRequest: false,
- ...mockedRequest,
- },
- };
-
- expect(RequestForm).toHaveBeenCalledWith(expect.objectContaining(expectedResult), {});
- });
- });
-
describe('when not working with request editing', () => {
beforeAll(() => {
mockedLocation.search = null;
@@ -203,7 +309,7 @@ describe('ViewRequest', () => {
describe('when current request is closed', () => {
describe('request is valid', () => {
- describe('TLR in enabled', () => {
+ describe('TLR is enabled', () => {
beforeAll(() => {
mockedConfig.records[0].value = {
titleLevelRequestsFeatureEnabled: true,
@@ -213,9 +319,17 @@ describe('ViewRequest', () => {
it('should render "Duplicate" button', () => {
expect(screen.getByText(labelIds.duplicateRequest)).toBeInTheDocument();
});
+
+ it('should trigger "onDuplicate"', async () => {
+ const duplicateButton = screen.getByText(labelIds.duplicateRequest);
+
+ await userEvent.click(duplicateButton);
+
+ expect(defaultProps.onDuplicate).toHaveBeenCalledWith(defaultProps.resources.selectedRequest.records[0]);
+ });
});
- describe('TLR in disabled', () => {
+ describe('TLR is disabled', () => {
beforeAll(() => {
mockedConfig.records[0].value = {
titleLevelRequestsFeatureEnabled: false,
@@ -505,6 +619,690 @@ describe('ViewRequest', () => {
});
});
+ describe('Component updating', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('When new request is loaded', () => {
+ const newProps = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [
+ {
+ ...mockedRequest,
+ instance: {
+ title: 'instanceTitle',
+ },
+ item: {
+ barcode: 'itemBarcode',
+ },
+ id: 'id',
+ },
+ ],
+ },
+ },
+ parentResources: {
+ configs: {
+ records: [
+ {
+ value: {
+ test: 1,
+ titleLevelRequestsFeatureEnabled: false,
+ },
+ }
+ ],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ const { rerender } = render();
+
+ rerender();
+ });
+
+ it('should trigger "joinRequest"', () => {
+ expect(defaultProps.joinRequest).toHaveBeenCalled();
+ });
+ });
+
+ describe('When new request is loading', () => {
+ const newProps = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: false,
+ records: [mockedRequest],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ const { rerender } = render();
+
+ rerender();
+ });
+
+ it('should not trigger "joinRequest"', () => {
+ expect(defaultProps.joinRequest).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('Request updating', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('When proxy functionality available', () => {
+ const props = {
+ ...defaultProps,
+ mutator: {
+ selectedRequest: {
+ PUT: jest.fn(() => Promise.resolve({})),
+ },
+ },
+ location: {
+ search: '?layer=edit',
+ layer: REQUEST_LAYERS.EDIT,
+ },
+ };
+ const sendCalloutMock = jest.fn();
+
+ beforeEach(() => {
+ jest.spyOn(React, 'createRef').mockReturnValue({
+ current: {
+ sendCallout: sendCalloutMock,
+ },
+ });
+ render();
+ });
+
+ it('should send correct data for record updating', async () => {
+ const saveButton = screen.getByTestId(testIds.saveRequestButton);
+ const dataToSubmit = {
+ proxy: mockedRequest.proxy,
+ proxyUserId: mockedRequest.proxyUserId,
+ id: mockedRequest.id,
+ instance: mockedRequest.instance,
+ item: mockedRequest.item,
+ metadata: mockedRequest.metadata,
+ pickupServicePointId: mockedRequest.pickupServicePointId,
+ requestLevel: mockedRequest.requestLevel,
+ status: mockedRequest.status,
+ holdShelfExpirationDate: mockedRequest.holdShelfExpirationDate,
+ requester: updatedRecordRequester.requester,
+ };
+
+ await userEvent.click(saveButton);
+
+ expect(props.mutator.selectedRequest.PUT).toHaveBeenCalledWith(dataToSubmit);
+ });
+ });
+
+ describe('When proxy functionality is not available', () => {
+ const props = {
+ ...defaultProps,
+ mutator: {
+ selectedRequest: {
+ PUT: jest.fn(() => Promise.resolve({})),
+ },
+ },
+ location: {
+ search: '?layer=edit',
+ layer: REQUEST_LAYERS.EDIT,
+ },
+ };
+ const sendCalloutMock = jest.fn();
+
+ beforeEach(() => {
+ isProxyFunctionalityAvailable.mockReturnValueOnce(false);
+ jest.spyOn(React, 'createRef').mockReturnValue({
+ current: {
+ sendCallout: sendCalloutMock,
+ },
+ });
+ render();
+ });
+
+ it('should send correct data for record updating', async () => {
+ const saveButton = screen.getByTestId(testIds.saveRequestButton);
+ const dataToSubmit = {
+ id: mockedRequest.id,
+ instance: mockedRequest.instance,
+ status: mockedRequest.status,
+ item: mockedRequest.item,
+ metadata: mockedRequest.metadata,
+ pickupServicePointId: mockedRequest.pickupServicePointId,
+ requestLevel: mockedRequest.requestLevel,
+ holdShelfExpirationDate: mockedRequest.holdShelfExpirationDate,
+ requester: updatedRecordRequester.requester,
+ };
+
+ await userEvent.click(saveButton);
+
+ expect(props.mutator.selectedRequest.PUT).toHaveBeenCalledWith(dataToSubmit);
+ });
+ });
+
+ describe('When error happens', () => {
+ const props = {
+ ...defaultProps,
+ mutator: {
+ selectedRequest: {
+ PUT: jest.fn(() => Promise.resolve({})),
+ },
+ },
+ location: {
+ layer: REQUEST_LAYERS.EDIT,
+ search: '?layer=edit',
+ },
+ onCloseEdit: jest.fn(() => throw new Error('error message')),
+ };
+ const sendCalloutMock = jest.fn();
+
+ beforeEach(() => {
+ jest.spyOn(React, 'createRef').mockReturnValue({
+ current: {
+ sendCallout: sendCalloutMock,
+ },
+ });
+ render();
+ });
+
+ it('should show error callout', async () => {
+ const saveButton = screen.getByTestId(testIds.saveRequestButton);
+
+ userEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(sendCalloutMock).toHaveBeenCalledWith(expect.objectContaining({ type: 'error' }));
+ });
+ });
+ });
+ });
+
+ describe('Request canceling via RequestFormContainer', () => {
+ const props = {
+ ...defaultProps,
+ mutator: {
+ selectedRequest: {
+ PUT: jest.fn(() => Promise.resolve({})),
+ },
+ },
+ location: {
+ search: '?layer=edit',
+ layer: REQUEST_LAYERS.EDIT,
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(async () => {
+ render();
+
+ const cancelButton = screen.getByTestId(testIds.cancelRequestButton);
+
+ await userEvent.click(cancelButton);
+ });
+
+ it('should send correct data for record canceling', () => {
+ expect(props.mutator.selectedRequest.PUT).toHaveBeenCalledWith(mockedRequest);
+ });
+
+ it('should trigger "onCloseEdit"', () => {
+ expect(props.onCloseEdit).toHaveBeenCalled();
+ });
+
+ it('should trigger "buildRecordsForHoldsShelfReport"', () => {
+ expect(props.buildRecordsForHoldsShelfReport).toHaveBeenCalled();
+ });
+ });
+
+ describe('Request canceling via action menu', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [
+ {
+ ...defaultProps.resources.selectedRequest.records[0],
+ status: requestStatuses.NOT_YET_FILLED,
+ },
+ ],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger CancelRequestDialog with correct "open" prop', async () => {
+ const cancelButton = screen.getByText(labelIds.cancelRequest);
+ const expectedProps = {
+ open: true,
+ };
+
+ CancelRequestDialog.mockClear();
+ await userEvent.click(cancelButton);
+
+ expect(CancelRequestDialog).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+ });
+
+ describe('Request moving', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [openRequest],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(async () => {
+ render();
+
+ const moveRequestButton = screen.getByText(labelIds.moveRequest);
+
+ await userEvent.click(moveRequestButton);
+ });
+
+ it('should trigger "MoveRequestManager" with correct props', () => {
+ const expectedProps = {
+ onMove: expect.any(Function),
+ onCancelMove: expect.any(Function),
+ request: props.resources.selectedRequest.records[0],
+ };
+
+ expect(MoveRequestManager).toHaveBeenCalledWith(expectedProps, {});
+ });
+
+ it('should not trigger "MoveRequestManager"', async () => {
+ const cancelMoveButton = screen.getByTestId(testIds.cancelMoveButton);
+
+ await userEvent.click(cancelMoveButton);
+
+ const moveRequestManager = screen.queryByTestId(testIds.moveRequestManager);
+
+ expect(moveRequestManager).not.toBeInTheDocument();
+ });
+
+ it('should trigger "history.push" after request moving', async () => {
+ const moveRequestButton = screen.getByTestId(testIds.moveRequestButton);
+ const expectedArgs = [`${requestQueueUrl}${props.location.search}`, { afterMove: true }];
+
+ await userEvent.click(moveRequestButton);
+
+ expect(props.history.push).toHaveBeenCalledWith(...expectedArgs);
+ });
+ });
+
+ describe('Request reordering', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [openRequest],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger "history.push" after clicking on reorder request button', async () => {
+ const reorderQueueButton = screen.getByText(labelIds.reorderQueue);
+ const expectedArgs = [
+ `${requestQueueUrl}${props.location.search}`,
+ { request: props.resources.selectedRequest.records[0] }
+ ];
+
+ await userEvent.click(reorderQueueButton);
+
+ expect(props.history.push).toHaveBeenCalledWith(...expectedArgs);
+ });
+ });
+
+ describe('Request editing', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [openRequest],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger "onEdit" after clicking on edit button', async () => {
+ const editButton = screen.getByText(labelIds.edit);
+
+ await userEvent.click(editButton);
+
+ expect(props.onEdit).toHaveBeenCalled();
+ });
+ });
+
+ describe('Request duplicating', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [openRequest],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger "onDuplicate" after clicking on duplicate button', async () => {
+ const duplicateButton = screen.getByText(labelIds.duplicateRequest);
+
+ await userEvent.click(duplicateButton);
+
+ expect(props.onDuplicate).toHaveBeenCalled();
+ });
+ });
+
+ describe('Detail menu', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [],
+ },
+ },
+ tagsEnabled: true,
+ tagsToggle: jest.fn(),
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger "PaneHeaderIconButton" with correct props', () => {
+ const expectedProps = {
+ icon: 'tag',
+ id: 'clickable-show-tags',
+ onClick: props.tagsToggle,
+ badgeCount: 0,
+ ariaLabel: [labelIds.showTags],
+ disabled: false,
+ };
+
+ expect(PaneHeaderIconButton).toHaveBeenCalledWith(expectedProps, {});
+ });
+ });
+
+ describe('Item details', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('When item information is provided', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [{
+ ...openRequest,
+ requestCount: 1,
+ loan: {
+ id: 'loanId',
+ },
+ }],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger "ItemDetail" with correct props', async () => {
+ const request = props.resources.selectedRequest.records[0];
+ const expectedProps = {
+ request,
+ item: request.item,
+ loan: request.loan,
+ requestCount: request.requestCount,
+ };
+
+ expect(ItemDetail).toHaveBeenCalledWith(expectedProps, {});
+ });
+ });
+
+ describe('When item information is not provided', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [{
+ ...openRequest,
+ item: undefined,
+ }],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should render no item information message', () => {
+ const noItemInformationMessage = screen.getByText(labelIds.noItemInformation, { exact: false });
+
+ expect(noItemInformationMessage).toBeInTheDocument();
+ });
+ });
+ });
+
+ describe('When cancellation reason is provided', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [{
+ ...openRequest,
+ cancellationReasonId: defaultProps.optionLists.cancellationReasons[0].id,
+ }],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should render cancellation reason label', () => {
+ const cancellationReasonLabel = screen.getByText(labelIds.cancellationReason);
+
+ expect(cancellationReasonLabel).toBeInTheDocument();
+ });
+
+ it('should render cancellation reason value', () => {
+ const cancellationReasonValue = screen.getByText(defaultProps.optionLists.cancellationReasons[0].name);
+
+ expect(cancellationReasonValue).toBeInTheDocument();
+ });
+ });
+
+ describe('When cancellation additional information is provided', () => {
+ const cancellationAdditionalInformation = 'cancellationAdditionalInformation';
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [{
+ ...openRequest,
+ cancellationReasonId: defaultProps.optionLists.cancellationReasons[0].id,
+ cancellationAdditionalInformation,
+ }],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should render cancellation additional information label', () => {
+ const cancellationInformationLabel = screen.getByText(labelIds.cancellationAdditionalInformation);
+
+ expect(cancellationInformationLabel).toBeInTheDocument();
+ });
+
+ it('should render cancellation additional information value', () => {
+ const cancellationInformationValue = screen.getByText(cancellationAdditionalInformation);
+
+ expect(cancellationInformationValue).toBeInTheDocument();
+ });
+ });
+
+ describe('When fulfilment preference is delivery', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [{
+ ...openRequest,
+ fulfillmentPreference: fulfillmentTypeMap.DELIVERY,
+ deliveryAddressTypeId: 'deliveryAddressTypeId',
+ }],
+ },
+ },
+ };
+ const deliveryAddressDetail = 'deliveryAddressDetail';
+
+ beforeEach(() => {
+ toUserAddress.mockReturnValueOnce(deliveryAddressDetail);
+ render();
+ });
+
+ it('should render "UserDetail" with delivery information', () => {
+ const request = props.resources.selectedRequest.records[0];
+ const expectedProps = {
+ deliveryAddress: deliveryAddressDetail,
+ user:request.requester,
+ proxy: request.proxy,
+ selectedDelivery: true,
+ patronGroups: props.patronGroups,
+ stripes: props.stripes,
+ request,
+ };
+
+ expect(UserDetail).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+ });
+
+ describe('When fulfilment preference is hold shelf', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [openRequest],
+ },
+ },
+ };
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should render "UserDetail" without delivery information', () => {
+ const request = props.resources.selectedRequest.records[0];
+ const expectedProps = {
+ deliveryAddress: undefined,
+ user:request.requester,
+ proxy: request.proxy,
+ selectedDelivery: false,
+ patronGroups: props.patronGroups,
+ stripes: props.stripes,
+ request,
+ };
+
+ expect(UserDetail).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+ });
+
+ describe('Spinner', () => {
+ const props = {
+ ...defaultProps,
+ resources: {
+ selectedRequest: {
+ hasLoaded: true,
+ records: [],
+ },
+ },
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ beforeEach(() => {
+ render();
+ });
+
+ it('should trigger spinner "Icon" with correct props', () => {
+ const expectedProps = {
+ icon: 'spinner-ellipsis',
+ width: '100px',
+ };
+
+ expect(Icon).toHaveBeenCalledWith(expectedProps, {});
+ });
+ });
+
describe('isAnyActionButtonVisible', () => {
describe('When visibility conditions are provided', () => {
it('should return true', () => {
diff --git a/src/components/FulfilmentPreference/FulfilmentPreference.js b/src/components/FulfilmentPreference/FulfilmentPreference.js
index 714d46cb..b2cb978f 100644
--- a/src/components/FulfilmentPreference/FulfilmentPreference.js
+++ b/src/components/FulfilmentPreference/FulfilmentPreference.js
@@ -26,11 +26,11 @@ const {
const FulfilmentPreference = ({
isEditForm,
- deliverySelected,
- deliveryAddress,
+ deliverySelected = false,
+ deliveryAddress = '',
onChangeAddress,
- deliveryLocations,
- fulfillmentTypeOptions,
+ deliveryLocations = [],
+ fulfillmentTypeOptions = [],
defaultDeliveryAddressTypeId,
changeDeliveryAddress,
requestTypes,
@@ -167,11 +167,4 @@ FulfilmentPreference.propTypes = {
deliverySelected: PropTypes.bool,
};
-FulfilmentPreference.defaultProps = {
- deliveryAddress: '',
- deliveryLocations: [],
- fulfillmentTypeOptions: [],
- deliverySelected: false,
-};
-
export default FulfilmentPreference;
diff --git a/src/components/PrintContent/PrintContent.js b/src/components/PrintContent/PrintContent.js
index 565bf9c3..9ff878d7 100644
--- a/src/components/PrintContent/PrintContent.js
+++ b/src/components/PrintContent/PrintContent.js
@@ -10,7 +10,7 @@ import css from './PrintContent.css';
const PrintContent = forwardRef(({
dataSource,
template,
- id,
+ id = 'printContent',
}, ref) => {
const templateFn = useMemo(() => buildTemplate(template), [template]);
@@ -43,8 +43,4 @@ PrintContent.propTypes = {
template: PropTypes.string.isRequired,
};
-PrintContent.defaultProps = {
- id: 'printContent',
-};
-
export default memo(PrintContent, isEqual);
diff --git a/src/components/RequestsFilters/PickupServicePointFilter/PickupServicePointFilter.js b/src/components/RequestsFilters/PickupServicePointFilter/PickupServicePointFilter.js
index dfabb668..7362de42 100644
--- a/src/components/RequestsFilters/PickupServicePointFilter/PickupServicePointFilter.js
+++ b/src/components/RequestsFilters/PickupServicePointFilter/PickupServicePointFilter.js
@@ -19,8 +19,8 @@ import {
} from '../../../constants';
const PickupServicePointFilter = ({
- activeValues,
- servicePoints,
+ activeValues = [],
+ servicePoints = [],
onChange,
onClear,
}) => {
@@ -67,9 +67,4 @@ PickupServicePointFilter.propTypes = {
onClear: PropTypes.func.isRequired,
};
-PickupServicePointFilter.defaultProps = {
- activeValues: [],
- servicePoints: [],
-};
-
export default PickupServicePointFilter;
diff --git a/src/components/RequestsFilters/RequestLevelFilter/RequestLevelFilter.js b/src/components/RequestsFilters/RequestLevelFilter/RequestLevelFilter.js
index 25c6f2b2..9c178dad 100644
--- a/src/components/RequestsFilters/RequestLevelFilter/RequestLevelFilter.js
+++ b/src/components/RequestsFilters/RequestLevelFilter/RequestLevelFilter.js
@@ -18,7 +18,7 @@ import {
} from '../../../constants';
const RequestLevelFilter = ({
- activeValues,
+ activeValues = [],
onChange,
onClear,
}) => {
@@ -63,8 +63,4 @@ RequestLevelFilter.propTypes = {
onClear: PropTypes.func.isRequired,
};
-RequestLevelFilter.defaultProps = {
- activeValues: [],
-};
-
export default RequestLevelFilter;
diff --git a/src/components/RequestsFilters/RequestsFilters.js b/src/components/RequestsFilters/RequestsFilters.js
index 72288f31..b3924df8 100644
--- a/src/components/RequestsFilters/RequestsFilters.js
+++ b/src/components/RequestsFilters/RequestsFilters.js
@@ -25,6 +25,7 @@ import {
} from '../../constants';
import { PickupServicePointFilter } from './PickupServicePointFilter';
+import { RetrievalServicePointFilter } from './RetrievalServicePointFilter';
import { RequestLevelFilter } from './RequestLevelFilter';
export default class RequestsFilters extends React.Component {
@@ -35,6 +36,7 @@ export default class RequestsFilters extends React.Component {
requestType: PropTypes.arrayOf(PropTypes.string),
tags: PropTypes.arrayOf(PropTypes.string),
pickupServicePoints: PropTypes.arrayOf(PropTypes.string),
+ retrievalServicePoints: PropTypes.arrayOf(PropTypes.string),
printStatus: PropTypes.arrayOf(PropTypes.string),
}).isRequired,
resources: PropTypes.object.isRequired,
@@ -65,6 +67,7 @@ export default class RequestsFilters extends React.Component {
requestType = [],
requestStatus = [],
pickupServicePoints = [],
+ retrievalServicePoints = [],
requestLevels = [],
printStatus = [],
},
@@ -146,6 +149,12 @@ export default class RequestsFilters extends React.Component {
onChange={onChange}
onClear={onClear}
/>
+
{isViewPrintDetailsEnabled && (
({
jest.mock('./PickupServicePointFilter', () => ({
PickupServicePointFilter: jest.fn((props) => ()),
}));
+jest.mock('./RetrievalServicePointFilter', () => ({
+ RetrievalServicePointFilter: jest.fn((props) => ()),
+}));
jest.mock('@folio/stripes/smart-components', () => ({
CheckboxFilter: jest.fn((props) => ()),
MultiSelectionFilter: jest.fn((props) => ()),
@@ -38,6 +42,7 @@ const props = {
requestStatus: ['Open'],
requestType: ['Hold'],
pickupServicePoints: ['1'],
+ retrievalServicePoints: ['1', '2'],
tags: ['Urgent'],
requestLevels: [],
printStatus: ['Printed'],
@@ -71,6 +76,7 @@ const testIds = {
requestLevelFilter: 'requestLevelFilter',
multiSelectionFilter: 'multiSelectionFilter',
pickupServicePointFilter: 'pickupServicePointFilter',
+ retrievalServicePointFilter: 'retrievalServicePointFilter',
};
const labelIds = {
[requestFilterTypes.REQUEST_TYPE]: 'ui-requests.requestMeta.type',
@@ -261,6 +267,21 @@ describe('RequestsFilters', () => {
});
});
+ describe('RetrievalServicePointFilter', () => {
+ it('should render RetrievalServicePointFilter', () => {
+ expect(screen.getByTestId(testIds.retrievalServicePointFilter)).toBeInTheDocument();
+ });
+
+ it('should trigger retrievalServicePointFilter with correct props', () => {
+ expect(RetrievalServicePointFilter).toHaveBeenCalledWith(expect.objectContaining({
+ 'data-testid': testIds.retrievalServicePointFilter,
+ activeValues: props.activeFilters.retrievalServicePoints,
+ onChange,
+ onClear,
+ }), {});
+ });
+ });
+
describe('When activeFilters prop is empty', () => {
const propsWithoutFilters = {
...props,
diff --git a/src/components/RequestsFilters/RequestsFiltersConfig.js b/src/components/RequestsFilters/RequestsFiltersConfig.js
index 8268f7d2..51de3546 100644
--- a/src/components/RequestsFilters/RequestsFiltersConfig.js
+++ b/src/components/RequestsFilters/RequestsFiltersConfig.js
@@ -43,6 +43,12 @@ export default [
values: [],
operator: '==',
},
+ {
+ name: requestFilterTypes.RETRIEVAL_SERVICE_POINT,
+ cql: 'item.retrievalServicePointId',
+ values: [],
+ operator: '==',
+ },
{
name: requestFilterTypes.PRINT_STATUS,
cql: 'printStatus',
diff --git a/src/components/RequestsFilters/RequestsFiltersConfig.test.js b/src/components/RequestsFilters/RequestsFiltersConfig.test.js
index b6d13606..ef3b05c0 100644
--- a/src/components/RequestsFilters/RequestsFiltersConfig.test.js
+++ b/src/components/RequestsFilters/RequestsFiltersConfig.test.js
@@ -81,6 +81,18 @@ describe('RequestsFiltersConfig', () => {
expect(pickupServicePointFilter).toEqual(expectedResult);
});
+ it('should have a filter for retrieval service point', () => {
+ const retrievalServicePointFilter = filtersConfig.find(f => f.name === requestFilterTypes.RETRIEVAL_SERVICE_POINT);
+ const expectedResult = {
+ name: 'retrievalServicePoints',
+ cql: 'item.retrievalServicePointId',
+ values: [],
+ operator: '==',
+ };
+
+ expect(retrievalServicePointFilter).toEqual(expectedResult);
+ });
+
describe('Print Status Filter configuration', () => {
it('should correctly match the filter configuration for printStatus', () => {
const printStatusFilter = filtersConfig.find(f => f.name === 'printStatus');
diff --git a/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.js b/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.js
new file mode 100644
index 00000000..7f8ad9ef
--- /dev/null
+++ b/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.js
@@ -0,0 +1,62 @@
+import { useCallback } from 'react';
+import { FormattedMessage } from 'react-intl';
+import { isEmpty } from 'lodash';
+import PropTypes from 'prop-types';
+
+import {
+ Accordion,
+ FilterAccordionHeader,
+} from '@folio/stripes/components';
+import {
+ MultiSelectionFilter,
+} from '@folio/stripes/smart-components';
+
+import {
+ requestFilterTypes,
+} from '../../../constants';
+
+import { useRetrievalServicePoints } from '../../../hooks';
+
+const RetrievalServicePointFilter = ({
+ activeValues,
+ onChange,
+ onClear,
+}) => {
+ const name = requestFilterTypes.RETRIEVAL_SERVICE_POINT;
+ const clearFilter = useCallback(() => {
+ onClear(name);
+ }, [name, onClear]);
+
+ const { retrievalSPsOptions } = useRetrievalServicePoints();
+
+ return (
+
+
}
+ name={name}
+ separator={false}
+ onClearFilter={clearFilter}
+ >
+
+
+
+ );
+};
+
+RetrievalServicePointFilter.propTypes = {
+ activeValues: PropTypes.arrayOf(PropTypes.string),
+ onChange: PropTypes.func.isRequired,
+ onClear: PropTypes.func.isRequired,
+};
+export default RetrievalServicePointFilter;
diff --git a/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.test.js b/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.test.js
new file mode 100644
index 00000000..6645e18f
--- /dev/null
+++ b/src/components/RequestsFilters/RetrievalServicePointFilter/RetrievalServicePointFilter.test.js
@@ -0,0 +1,86 @@
+import {
+ render,
+ screen,
+} from '@folio/jest-config-stripes/testing-library/react';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
+
+import {
+ Accordion,
+ FilterAccordionHeader,
+} from '@folio/stripes/components';
+
+import RetrievalServicePointFilter from './RetrievalServicePointFilter';
+import { requestFilterTypes } from '../../../constants';
+
+jest.mock('../../../hooks', () => ({
+ ...jest.requireActual('../../../hooks'),
+ useRetrievalServicePoints: jest.fn().mockReturnValue([
+ {
+ value: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f',
+ label: 'Circ desk 1',
+ },
+ {
+ value: '9d1b77e8-f02e-4b7f-b296-3f2042ddac54',
+ label: 'Circ desk 2',
+ },
+ ]),
+}));
+
+const activeValues = ['test', 'test2'];
+const onChange = jest.fn();
+const onClear = jest.fn();
+const testIds = {
+ retrievalServicePointAccordionButton: 'retrievalServicePointAccordionButton',
+};
+
+describe('RetrievalServicePointFilter', () => {
+ beforeEach(() => {
+ onChange.mockClear();
+ onClear.mockClear();
+ render(
+
+ );
+ });
+
+ it('should render "Accordion" with correct props', () => {
+ const expectedProps = {
+ id: requestFilterTypes.RETRIEVAL_SERVICE_POINT,
+ name: requestFilterTypes.RETRIEVAL_SERVICE_POINT,
+ header: FilterAccordionHeader,
+ separator: false,
+ onClearFilter: expect.any(Function),
+ };
+
+ expect(Accordion).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+
+ it('should render MultiSelectionFilter', () => {
+ const MultiSelectionFilter = screen.getByText('MultiSelectionFilter');
+
+ expect(MultiSelectionFilter).toBeInTheDocument();
+ });
+
+ it('should perform onClear event', async () => {
+ const retrievalServicePointsButton = screen.getByTestId(testIds.retrievalServicePointAccordionButton);
+
+ await userEvent.click(retrievalServicePointsButton);
+
+ expect(onClear).toHaveBeenCalledWith(requestFilterTypes.RETRIEVAL_SERVICE_POINT);
+ });
+
+ describe('MultiSelectionFilter activeValues', () => {
+ activeValues.forEach(value => {
+ it(`should render "${value}"`, () => {
+ const activeValue = screen.getByText(value, {
+ exact: false,
+ });
+
+ expect(activeValue).toBeInTheDocument();
+ });
+ });
+ });
+});
diff --git a/src/components/RequestsFilters/RetrievalServicePointFilter/index.js b/src/components/RequestsFilters/RetrievalServicePointFilter/index.js
new file mode 100644
index 00000000..c397fd61
--- /dev/null
+++ b/src/components/RequestsFilters/RetrievalServicePointFilter/index.js
@@ -0,0 +1 @@
+export { default as RetrievalServicePointFilter } from './RetrievalServicePointFilter';
diff --git a/src/components/SortableList/SortableList.js b/src/components/SortableList/SortableList.js
index 6ab59862..cdb51867 100644
--- a/src/components/SortableList/SortableList.js
+++ b/src/components/SortableList/SortableList.js
@@ -14,10 +14,10 @@ import draggableRowFormatter from './draggableRowFormatter';
export default function SortableList(props) {
const {
- droppableId,
+ droppableId = uniqueId('droppable'),
onDragEnd,
- rowFormatter,
- isRowDraggable,
+ rowFormatter = draggableRowFormatter,
+ isRowDraggable = () => true,
rowProps,
visibleColumns: originalVisibleColumns,
columnWidths: originalColumnWidths,
@@ -73,12 +73,6 @@ export default function SortableList(props) {
);
}
-SortableList.defaultProps = {
- droppableId: uniqueId('droppable'),
- rowFormatter: draggableRowFormatter,
- isRowDraggable: () => true,
-};
-
SortableList.propTypes = {
droppableId: PropTypes.string,
onDragEnd: PropTypes.func,
diff --git a/src/components/TitleInformation/TitleInformation.js b/src/components/TitleInformation/TitleInformation.js
index fba65c0f..3730b288 100644
--- a/src/components/TitleInformation/TitleInformation.js
+++ b/src/components/TitleInformation/TitleInformation.js
@@ -33,15 +33,15 @@ export const getIdentifiers = (data, separator, limit) => data.slice(0, limit).m
const TitleInformation = (props) => {
const {
- titleLevelRequestsLink,
+ titleLevelRequestsLink = true,
holdingsRecordId,
instanceId,
titleLevelRequestsCount,
title,
- contributors,
- publications,
- editions,
- identifiers,
+ contributors = [],
+ publications = [],
+ editions = [],
+ identifiers = [],
intl:{
formatMessage,
},
@@ -95,14 +95,6 @@ const TitleInformation = (props) => {
);
};
-TitleInformation.defaultProps = {
- contributors: [],
- publications: [],
- editions: [],
- identifiers: [],
- titleLevelRequestsLink: true,
-};
-
TitleInformation.propTypes = {
titleLevelRequestsLink: PropTypes.bool,
titleLevelRequestsCount: PropTypes.number.isRequired,
diff --git a/src/constants.js b/src/constants.js
index 5ee53821..7a89e6cd 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -242,6 +242,7 @@ export const requestFilterTypes = {
REQUEST_STATUS: 'requestStatus',
REQUEST_LEVELS: 'requestLevels',
PICKUP_SERVICE_POINT: 'pickupServicePoints',
+ RETRIEVAL_SERVICE_POINT: 'retrievalServicePoints',
PRINT_STATUS: 'printStatus',
};
@@ -431,3 +432,6 @@ export const SETTINGS_SCOPES = {
export const SETTINGS_KEYS = {
GENERAL_TLR: 'generalTlr',
};
+
+export const LOCATIONS_API = 'locations';
+export const SERVICE_POINTS_API = 'service-points';
diff --git a/src/deprecated/components/RequestsFilters/RequestsFilters.js b/src/deprecated/components/RequestsFilters/RequestsFilters.js
new file mode 100644
index 00000000..2a2cb682
--- /dev/null
+++ b/src/deprecated/components/RequestsFilters/RequestsFilters.js
@@ -0,0 +1,172 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { FormattedMessage } from 'react-intl';
+import {
+ get,
+ isEmpty,
+ sortBy,
+} from 'lodash';
+
+import {
+ Accordion,
+ AccordionSet,
+ FilterAccordionHeader,
+} from '@folio/stripes/components';
+import {
+ CheckboxFilter,
+ MultiSelectionFilter,
+} from '@folio/stripes/smart-components';
+
+import {
+ requestFilterTypes,
+ requestPrintStatusFilters,
+ requestStatusFilters,
+ requestTypeFilters,
+} from '../../../constants';
+
+import { PickupServicePointFilter } from '../../../components/RequestsFilters/PickupServicePointFilter';
+import { RequestLevelFilter } from '../../../components/RequestsFilters/RequestLevelFilter';
+
+export default class RequestsFilters extends React.Component {
+ static propTypes = {
+ activeFilters: PropTypes.shape({
+ requestStatus: PropTypes.arrayOf(PropTypes.string),
+ requestLevels: PropTypes.arrayOf(PropTypes.string),
+ requestType: PropTypes.arrayOf(PropTypes.string),
+ tags: PropTypes.arrayOf(PropTypes.string),
+ pickupServicePoints: PropTypes.arrayOf(PropTypes.string),
+ printStatus: PropTypes.arrayOf(PropTypes.string),
+ }).isRequired,
+ resources: PropTypes.object.isRequired,
+ onChange: PropTypes.func.isRequired,
+ onClear: PropTypes.func.isRequired,
+ titleLevelRequestsFeatureEnabled: PropTypes.bool.isRequired,
+ isViewPrintDetailsEnabled: PropTypes.bool.isRequired,
+ };
+
+ transformRequestFilterOptions = (source = []) => {
+ return source.map(({ label, value }) => ({
+ label: ,
+ value,
+ }));
+ };
+
+ transformTagsOptions = () => {
+ const tags = get(this.props.resources, 'tags.records', [])
+ .map(({ label }) => ({ label, value: label }));
+
+ return sortBy(tags, 'label');
+ };
+
+ render() {
+ const {
+ activeFilters: {
+ tags = [],
+ requestType = [],
+ requestStatus = [],
+ pickupServicePoints = [],
+ requestLevels = [],
+ printStatus = [],
+ },
+ onChange,
+ onClear,
+ titleLevelRequestsFeatureEnabled,
+ isViewPrintDetailsEnabled,
+ } = this.props;
+
+ return (
+
+ }
+ name={requestFilterTypes.REQUEST_TYPE}
+ separator={false}
+ onClearFilter={() => onClear(requestFilterTypes.REQUEST_TYPE)}
+ >
+
+
+ }
+ name={requestFilterTypes.REQUEST_STATUS}
+ separator={false}
+ onClearFilter={() => onClear(requestFilterTypes.REQUEST_STATUS)}
+ >
+
+
+ {titleLevelRequestsFeatureEnabled && (
+
+ )}
+ }
+ name={requestFilterTypes.TAGS}
+ separator={false}
+ onClearFilter={() => onClear(requestFilterTypes.TAGS)}
+ >
+
+
+
+ {isViewPrintDetailsEnabled && (
+ }
+ name={requestFilterTypes.PRINT_STATUS}
+ separator={false}
+ onClearFilter={() => onClear(requestFilterTypes.PRINT_STATUS)}
+ >
+
+
+ )}
+
+ );
+ }
+}
diff --git a/src/deprecated/components/RequestsFilters/RequestsFilters.test.js b/src/deprecated/components/RequestsFilters/RequestsFilters.test.js
new file mode 100644
index 00000000..58b0f8c9
--- /dev/null
+++ b/src/deprecated/components/RequestsFilters/RequestsFilters.test.js
@@ -0,0 +1,383 @@
+import {
+ render,
+ screen,
+} from '@folio/jest-config-stripes/testing-library/react';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
+
+import {
+ Accordion,
+} from '@folio/stripes/components';
+import {
+ CheckboxFilter,
+ MultiSelectionFilter,
+} from '@folio/stripes/smart-components';
+
+import RequestsFilters from './RequestsFilters';
+import { RequestLevelFilter } from '../../../components/RequestsFilters/RequestLevelFilter';
+import { PickupServicePointFilter } from '../../../components/RequestsFilters/PickupServicePointFilter';
+
+import {
+ requestFilterTypes,
+} from '../../../constants';
+
+jest.mock('../../../components/RequestsFilters/RequestLevelFilter', () => ({
+ RequestLevelFilter: jest.fn((props) => ()),
+}));
+jest.mock('../../../components/RequestsFilters/PickupServicePointFilter', () => ({
+ PickupServicePointFilter: jest.fn((props) => ()),
+}));
+jest.mock('@folio/stripes/smart-components', () => ({
+ CheckboxFilter: jest.fn((props) => ()),
+ MultiSelectionFilter: jest.fn((props) => ()),
+}));
+
+const onChange = jest.fn();
+const onClear = jest.fn();
+const props = {
+ activeFilters: {
+ requestStatus: ['Open'],
+ requestType: ['Hold'],
+ pickupServicePoints: ['1'],
+ tags: ['Urgent'],
+ requestLevels: [],
+ printStatus: ['Printed'],
+ },
+ onChange,
+ onClear,
+ resources: {
+ servicePoints: {
+ records: [{
+ id: '1',
+ name: 'Service Point 1',
+ }],
+ },
+ tags: {
+ records: [{
+ label: 'Urgent',
+ }],
+ },
+ },
+ titleLevelRequestsFeatureEnabled: false,
+ isViewPrintDetailsEnabled: false,
+};
+const testIds = {
+ [requestFilterTypes.REQUEST_TYPE]: requestFilterTypes.REQUEST_TYPE,
+ [`${requestFilterTypes.REQUEST_TYPE}Filter`]: `${requestFilterTypes.REQUEST_TYPE}Filter`,
+ [requestFilterTypes.REQUEST_STATUS]: requestFilterTypes.REQUEST_STATUS,
+ [`${requestFilterTypes.REQUEST_STATUS}Filter`]: `${requestFilterTypes.REQUEST_STATUS}Filter`,
+ [requestFilterTypes.TAGS]: requestFilterTypes.TAGS,
+ [requestFilterTypes.PRINT_STATUS]: requestFilterTypes.PRINT_STATUS,
+ [`${requestFilterTypes.PRINT_STATUS}Filter`]: `${requestFilterTypes.PRINT_STATUS}Filter`,
+ requestLevelFilter: 'requestLevelFilter',
+ multiSelectionFilter: 'multiSelectionFilter',
+ pickupServicePointFilter: 'pickupServicePointFilter',
+};
+const labelIds = {
+ [requestFilterTypes.REQUEST_TYPE]: 'ui-requests.requestMeta.type',
+ [requestFilterTypes.REQUEST_STATUS]: 'ui-requests.requestMeta.status',
+ [requestFilterTypes.TAGS]: 'ui-requests.requestMeta.tags',
+ [requestFilterTypes.PRINT_STATUS]: 'ui-requests.requestMeta.printStatus',
+};
+
+describe('RequestsFilters', () => {
+ beforeEach(() => {
+ render();
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('Request type accordion', () => {
+ it('should render request type accordion', () => {
+ expect(screen.getByTestId(testIds[requestFilterTypes.REQUEST_TYPE])).toBeInTheDocument();
+ });
+
+ it('should render label for request type accordion', () => {
+ expect(screen.getByText(labelIds[requestFilterTypes.REQUEST_TYPE])).toBeInTheDocument();
+ });
+
+ it('should trigger request type accordion with correct props', () => {
+ expect(Accordion).toHaveBeenNthCalledWith(1, expect.objectContaining({
+ displayClearButton: true,
+ id: requestFilterTypes.REQUEST_TYPE,
+ 'data-testid': requestFilterTypes.REQUEST_TYPE,
+ name: requestFilterTypes.REQUEST_TYPE,
+ onClearFilter: expect.any(Function),
+ header: expect.any(Function),
+ separator: false,
+ }), {});
+ });
+
+ it('should be called onClearFilter with request filter types Request type', async () => {
+ await userEvent.click(screen.getByTestId(`${testIds[requestFilterTypes.REQUEST_TYPE]}Button`));
+
+ expect(onClear).toHaveBeenCalledWith(requestFilterTypes.REQUEST_TYPE);
+ });
+
+ it('should render CheckboxFilter for Request type accordion', () => {
+ expect(screen.getByTestId(testIds[`${requestFilterTypes.REQUEST_TYPE}Filter`])).toBeInTheDocument();
+ });
+
+ it('should trigger CheckboxFilter for Request type accordion with correct props', () => {
+ expect(CheckboxFilter).toHaveBeenNthCalledWith(1, expect.objectContaining({
+ 'data-testid': testIds[`${requestFilterTypes.REQUEST_TYPE}Filter`],
+ name: requestFilterTypes.REQUEST_TYPE,
+ selectedValues: props.activeFilters[requestFilterTypes.REQUEST_TYPE],
+ onChange,
+ }), {});
+ });
+ });
+
+ describe('Request status accordion', () => {
+ it('should render request status accordion', () => {
+ expect(screen.getByTestId(testIds[requestFilterTypes.REQUEST_STATUS])).toBeInTheDocument();
+ });
+
+ it('should render label for request status accordion', () => {
+ expect(screen.getByText(labelIds[requestFilterTypes.REQUEST_STATUS])).toBeInTheDocument();
+ });
+
+ it('should trigger request status accordion with correct props', () => {
+ expect(Accordion).toHaveBeenNthCalledWith(2, expect.objectContaining({
+ displayClearButton: true,
+ id: requestFilterTypes.REQUEST_STATUS,
+ 'data-testid': requestFilterTypes.REQUEST_STATUS,
+ name: requestFilterTypes.REQUEST_STATUS,
+ onClearFilter: expect.any(Function),
+ header: expect.any(Function),
+ separator: false,
+ }), {});
+ });
+
+ it('should be called onClearFilter with request filter types Request status', async () => {
+ await userEvent.click(screen.getByTestId(`${testIds[requestFilterTypes.REQUEST_STATUS]}Button`));
+
+ expect(onClear).toHaveBeenCalledWith(requestFilterTypes.REQUEST_STATUS);
+ });
+
+ it('should render CheckboxFilter for Request status accordion', () => {
+ expect(screen.getByTestId(testIds[`${requestFilterTypes.REQUEST_STATUS}Filter`])).toBeInTheDocument();
+ });
+
+ it('should trigger CheckboxFilter for Request status accordion with correct props', () => {
+ expect(CheckboxFilter).toHaveBeenNthCalledWith(1, expect.objectContaining({
+ 'data-testid': testIds[`${requestFilterTypes.REQUEST_TYPE}Filter`],
+ name: requestFilterTypes.REQUEST_TYPE,
+ selectedValues: props.activeFilters[requestFilterTypes.REQUEST_TYPE],
+ onChange,
+ }), {});
+ });
+ });
+
+ describe('Tags accordion', () => {
+ it('should render tags accordion', () => {
+ expect(screen.getByTestId(testIds[requestFilterTypes.TAGS])).toBeInTheDocument();
+ });
+
+ it('should render label for tags accordion', () => {
+ expect(screen.getByText(labelIds[requestFilterTypes.TAGS])).toBeInTheDocument();
+ });
+
+ it('should trigger tags accordion with correct props', () => {
+ expect(Accordion).toHaveBeenNthCalledWith(3, expect.objectContaining({
+ displayClearButton: true,
+ id: requestFilterTypes.TAGS,
+ 'data-testid': requestFilterTypes.TAGS,
+ name: requestFilterTypes.TAGS,
+ onClearFilter: expect.any(Function),
+ header: expect.any(Function),
+ separator: false,
+ }), {});
+ });
+
+ it('should be called onClearFilter with request filter types tags', async () => {
+ await userEvent.click(screen.getByTestId(`${testIds[requestFilterTypes.TAGS]}Button`));
+
+ expect(onClear).toHaveBeenCalledWith(requestFilterTypes.TAGS);
+ });
+
+ it('should render MultiSelectionFilter for tags accordion', () => {
+ expect(screen.getByTestId(testIds.multiSelectionFilter)).toBeInTheDocument();
+ });
+
+ it('should trigger MultiSelectionFilter for Tags accordion with correct props', () => {
+ expect(MultiSelectionFilter).toHaveBeenCalledWith(expect.objectContaining({
+ 'data-testid': testIds.multiSelectionFilter,
+ dataOptions: [{
+ label: 'Urgent',
+ value: 'Urgent',
+ }],
+ name: requestFilterTypes.TAGS,
+ selectedValues: props.activeFilters.tags,
+ onChange,
+ ariaLabelledBy: requestFilterTypes.TAGS,
+ }), {});
+ });
+ });
+
+ describe('RequestLevelFilter', () => {
+ it('should not render RequestLevelFilter', () => {
+ expect(screen.queryByTestId(testIds.requestLevelFilter)).not.toBeInTheDocument();
+ });
+
+ describe('with titleLevelRequestsFeatureEnabled true', () => {
+ const currentProps = {
+ ...props,
+ titleLevelRequestsFeatureEnabled: true,
+ };
+ beforeEach(() => {
+ render();
+ });
+
+ it('should render RequestLevelFilter', () => {
+ expect(screen.getByTestId(testIds.requestLevelFilter)).toBeInTheDocument();
+ });
+
+ it('should trigger RequestLevelFilter with correct props', () => {
+ expect(RequestLevelFilter).toHaveBeenCalledWith(expect.objectContaining({
+ 'data-testid': testIds.requestLevelFilter,
+ activeValues: props.activeFilters.requestLevels,
+ onChange,
+ onClear,
+ }), {});
+ });
+ });
+ });
+
+ describe('PickupServicePointFilter', () => {
+ it('should render PickupServicePointFilter', () => {
+ expect(screen.getByTestId(testIds.pickupServicePointFilter)).toBeInTheDocument();
+ });
+
+ it('should trigger PickupServicePointFilter with correct props', () => {
+ expect(PickupServicePointFilter).toHaveBeenCalledWith(expect.objectContaining({
+ 'data-testid': testIds.pickupServicePointFilter,
+ activeValues: props.activeFilters.pickupServicePoints,
+ servicePoints: props.resources.servicePoints.records,
+ onChange,
+ onClear,
+ }), {});
+ });
+ });
+
+ describe('When activeFilters prop is empty', () => {
+ const propsWithoutFilters = {
+ ...props,
+ activeFilters: {},
+ titleLevelRequestsFeatureEnabled: true,
+ };
+ const checkboxFilterCallOrder = {
+ requestTypeCheckbox: 1,
+ requestStatusCheckbox: 2,
+ };
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+
+ render(
+
+ );
+ });
+
+ it('should trigger tags filter with correct selectedValues prop', () => {
+ const expectedProps = {
+ selectedValues: [],
+ };
+
+ expect(MultiSelectionFilter).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+
+ it('should trigger request type filter with correct selectedValues prop', () => {
+ const expectedProps = {
+ selectedValues: [],
+ };
+
+ expect(CheckboxFilter).toHaveBeenNthCalledWith(checkboxFilterCallOrder.requestTypeCheckbox, expect.objectContaining(expectedProps), {});
+ });
+
+ it('should trigger request status filter with correct selectedValues prop', () => {
+ const expectedProps = {
+ selectedValues: [],
+ };
+
+ expect(CheckboxFilter).toHaveBeenNthCalledWith(checkboxFilterCallOrder.requestStatusCheckbox, expect.objectContaining(expectedProps), {});
+ });
+
+ it('should trigger pickup service point filter with correct activeValues prop', () => {
+ const expectedProps = {
+ activeValues: [],
+ };
+
+ expect(PickupServicePointFilter).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+
+ it('should trigger request level filter with correct activeValues prop', () => {
+ const expectedProps = {
+ activeValues: [],
+ };
+
+ expect(RequestLevelFilter).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
+ });
+ });
+
+ describe('Print status accordion', () => {
+ describe('when isViewPrintDetailsEnabled is disabled', () => {
+ it('should not render Print status accordion', () => {
+ expect(screen.queryByTestId(testIds[requestFilterTypes.PRINT_STATUS])).not.toBeInTheDocument();
+ });
+ });
+
+ describe('when isViewPrintDetailsEnabled is enabled', () => {
+ const currentProps = {
+ ...props,
+ isViewPrintDetailsEnabled: true,
+ };
+ beforeEach(() => {
+ jest.clearAllMocks();
+ render();
+ });
+
+ it('should render Print status accordion', () => {
+ expect(screen.getByTestId(testIds[requestFilterTypes.PRINT_STATUS])).toBeInTheDocument();
+ });
+
+ it('should render label for Print status accordion', () => {
+ expect(screen.getByText(labelIds[requestFilterTypes.PRINT_STATUS])).toBeInTheDocument();
+ });
+
+ it('should trigger Print status accordion with correct props', () => {
+ expect(Accordion).toHaveBeenNthCalledWith(4, expect.objectContaining({
+ displayClearButton: true,
+ id: requestFilterTypes.PRINT_STATUS,
+ 'data-testid': requestFilterTypes.PRINT_STATUS,
+ name: requestFilterTypes.PRINT_STATUS,
+ onClearFilter: expect.any(Function),
+ header: expect.any(Function),
+ separator: false,
+ }), {});
+ });
+
+ it('should be called onClearFilter with request filter types Print status', async () => {
+ await userEvent.click(screen.getByTestId(`${testIds[requestFilterTypes.PRINT_STATUS]}Button`));
+
+ expect(onClear).toHaveBeenCalledWith(requestFilterTypes.PRINT_STATUS);
+ });
+
+ it('should render CheckboxFilter for Print status accordion', () => {
+ expect(screen.getByTestId(testIds[`${requestFilterTypes.PRINT_STATUS}Filter`])).toBeInTheDocument();
+ });
+
+ it('should trigger CheckboxFilter for Print status accordion with correct props', () => {
+ expect(CheckboxFilter).toHaveBeenNthCalledWith(3, expect.objectContaining({
+ 'data-testid': testIds[`${requestFilterTypes.PRINT_STATUS}Filter`],
+ name: requestFilterTypes.PRINT_STATUS,
+ selectedValues: props.activeFilters[requestFilterTypes.PRINT_STATUS],
+ onChange,
+ }), {});
+ });
+ });
+ });
+});
diff --git a/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.js b/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.js
new file mode 100644
index 00000000..56108183
--- /dev/null
+++ b/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.js
@@ -0,0 +1,59 @@
+import { requestFilterTypes } from '../../../constants';
+
+export const escapingForSpecialCharactersWhichCanBreakCQL = (string = '') => string.replace(/[\\"?*]/g, '\\$&');
+
+export default [
+ {
+ name: 'requestType',
+ cql: 'requestType',
+ values: [],
+ operator: '==',
+ },
+ {
+ label: 'ui-requests.requestMeta.status',
+ name: 'requestStatus',
+ cql: 'status',
+ values: [],
+ operator: '==',
+ },
+ {
+ name: requestFilterTypes.REQUEST_LEVELS,
+ cql: 'requestLevel',
+ values: [],
+ operator: '==',
+ },
+ {
+ name: 'tags',
+ cql: 'tags.tagList',
+ values: [],
+ operator: '==',
+ parse: (value) => {
+ if (Array.isArray(value)) {
+ return `(tags.tagList==(${value.map(v => `"*\\"*${escapingForSpecialCharactersWhichCanBreakCQL(v)}*\\"*"`).join(' or ')}))`;
+ } else {
+ return `(tags.tagList==("*\\"*${escapingForSpecialCharactersWhichCanBreakCQL(value)}*\\"*"))`;
+ }
+ }
+ },
+ {
+ name: requestFilterTypes.PICKUP_SERVICE_POINT,
+ cql: 'pickupServicePointId',
+ values: [],
+ operator: '==',
+ },
+ {
+ name: requestFilterTypes.PRINT_STATUS,
+ cql: 'printStatus',
+ values: [],
+ operator: '==',
+ parse: (value) => {
+ if (value.length === 1 && value.includes('Printed')) {
+ return 'printDetails.isPrinted==true';
+ } else if (value.length === 1 && value.includes('Not printed')) {
+ return 'cql.allRecords=1 NOT printDetails.isPrinted=""';
+ } else {
+ return '(cql.allRecords=1 NOT printDetails.printed="" or printDetails.printed==true)';
+ }
+ }
+ },
+];
diff --git a/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.test.js b/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.test.js
new file mode 100644
index 00000000..503dd2ef
--- /dev/null
+++ b/src/deprecated/components/RequestsFilters/RequestsFiltersConfig.test.js
@@ -0,0 +1,144 @@
+import filtersConfig, {
+ escapingForSpecialCharactersWhichCanBreakCQL,
+} from './RequestsFiltersConfig';
+
+import {
+ requestFilterTypes,
+} from '../../../constants';
+
+describe('RequestsFiltersConfig', () => {
+ it('should have a filter for requestType', () => {
+ const requestTypeFilter = filtersConfig.find(f => f.name === 'requestType');
+ const expectedResult = {
+ name: 'requestType',
+ cql: 'requestType',
+ values: [],
+ operator: '==',
+ };
+
+ expect(requestTypeFilter).toEqual(expectedResult);
+ });
+
+ it('should have a filter for requestStatus', () => {
+ const requestStatusFilter = filtersConfig.find(f => f.name === 'requestStatus');
+ const expectedResult = {
+ name: 'requestStatus',
+ cql: 'status',
+ values: [],
+ operator: '==',
+ label: 'ui-requests.requestMeta.status',
+ };
+
+ expect(requestStatusFilter).toEqual(expectedResult);
+ });
+
+ it('should have a filter for request levels', () => {
+ const requestLevelsFilter = filtersConfig.find(f => f.name === requestFilterTypes.REQUEST_LEVELS);
+ const expectedResult = {
+ name: 'requestLevels',
+ cql: 'requestLevel',
+ values: [],
+ operator: '==',
+ };
+
+ expect(requestLevelsFilter).toEqual(expectedResult);
+ });
+
+ it('should return the expected query string for a single tag', () => {
+ const tagsFilter = filtersConfig.find(f => f.name === 'tags');
+ const expectedResult = {
+ name: 'tags',
+ cql: 'tags.tagList',
+ values: [],
+ operator: '==',
+ parse: expect.any(Function),
+ };
+
+ expect(tagsFilter).toEqual(expectedResult);
+ });
+
+ it('should return the expected query string for a single tag', () => {
+ const tagsFilter = filtersConfig.find(f => f.name === 'tags');
+
+ expect(tagsFilter.parse('tag1')).toEqual('(tags.tagList==("*\\"*tag1*\\"*"))');
+ });
+
+ it('should return the expected query string for an array of tags', () => {
+ const tagsFilter = filtersConfig.find(f => f.name === 'tags');
+
+ expect(tagsFilter.parse(['tag1', 'tag2'])).toEqual('(tags.tagList==("*\\"*tag1*\\"*" or "*\\"*tag2*\\"*"))');
+ });
+
+ it('should have a filter for pickup service point', () => {
+ const pickupServicePointFilter = filtersConfig.find(f => f.name === requestFilterTypes.PICKUP_SERVICE_POINT);
+ const expectedResult = {
+ name: 'pickupServicePoints',
+ cql: 'pickupServicePointId',
+ values: [],
+ operator: '==',
+ };
+
+ expect(pickupServicePointFilter).toEqual(expectedResult);
+ });
+
+ describe('Print Status Filter configuration', () => {
+ it('should correctly match the filter configuration for printStatus', () => {
+ const printStatusFilter = filtersConfig.find(f => f.name === 'printStatus');
+ const expectedResult = {
+ name: 'printStatus',
+ cql: 'printStatus',
+ values: [],
+ operator: '==',
+ parse: expect.any(Function),
+ };
+
+ expect(printStatusFilter).toEqual(expectedResult);
+ });
+
+ it('should generate the correct query string for the "Printed" filter', () => {
+ const printStatusFilter = filtersConfig.find(f => f.name === 'printStatus');
+
+ expect(printStatusFilter.parse(['Printed'])).toEqual('printDetails.isPrinted==true');
+ });
+
+ it('should generate the correct query string for the "Not printed" filter', () => {
+ const printStatusFilter = filtersConfig.find(f => f.name === 'printStatus');
+
+ expect(printStatusFilter.parse(['Not printed'])).toEqual('cql.allRecords=1 NOT printDetails.isPrinted=""');
+ });
+
+ it('should generate the correct query string for a combination of "Printed" and "Not printed" filters', () => {
+ const printStatusFilter = filtersConfig.find(f => f.name === 'printStatus');
+
+ expect(printStatusFilter.parse(['Printed', 'Not printed']))
+ .toEqual('(cql.allRecords=1 NOT printDetails.printed="" or printDetails.printed==true)');
+ });
+ });
+
+ describe('escapingForSpecialCharactersWhichCanBreakCQL', () => {
+ it('should return empty string', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL()).toBe('');
+ });
+
+ it('should escape \\', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL('\\')).toBe('\\\\');
+ });
+
+ it('should escape "', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL('"')).toBe('\\"');
+ });
+
+ it('should escape ?', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL('?')).toBe('\\?');
+ });
+
+ it('should escape *', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL('*')).toBe('\\*');
+ });
+
+ it('should escape special characters in string', () => {
+ expect(escapingForSpecialCharactersWhichCanBreakCQL('(test") + [test] * ? \\ (){}[]-_=+<>/?.,~'))
+ .toBe('(test\\") + [test] \\* \\? \\\\ (){}[]-_=+<>/\\?.,~');
+ });
+ });
+});
diff --git a/src/deprecated/components/RequestsFilters/index.js b/src/deprecated/components/RequestsFilters/index.js
new file mode 100644
index 00000000..1ec650c6
--- /dev/null
+++ b/src/deprecated/components/RequestsFilters/index.js
@@ -0,0 +1,2 @@
+export { default as RequestsFilters } from './RequestsFilters';
+export { default as RequestsFiltersConfig } from './RequestsFiltersConfig';
diff --git a/src/deprecated/routes/RequestsRoute/RequestsRoute.js b/src/deprecated/routes/RequestsRoute/RequestsRoute.js
index 8f25e6f3..f53829f9 100644
--- a/src/deprecated/routes/RequestsRoute/RequestsRoute.js
+++ b/src/deprecated/routes/RequestsRoute/RequestsRoute.js
@@ -94,7 +94,7 @@ import {
import {
RequestsFilters,
RequestsFiltersConfig,
-} from '../../../components/RequestsFilters';
+} from '../../components/RequestsFilters';
import RequestsRouteShortcutsWrapper from '../../../components/RequestsRouteShortcutsWrapper';
import {
isReorderableRequest,
diff --git a/src/deprecated/routes/RequestsRoute/RequestsRoute.test.js b/src/deprecated/routes/RequestsRoute/RequestsRoute.test.js
index 76fb1d64..51834545 100644
--- a/src/deprecated/routes/RequestsRoute/RequestsRoute.test.js
+++ b/src/deprecated/routes/RequestsRoute/RequestsRoute.test.js
@@ -155,7 +155,7 @@ jest.mock('../../../components', () => ({
}),
PrintContent: jest.fn(({ printContentTestId }) => PrintContent
)
}));
-jest.mock('../../../components/RequestsFilters/RequestsFilters', () => ({ onClear }) => {
+jest.mock('../../components/RequestsFilters/RequestsFilters', () => ({ onClear }) => {
return (
RequestsFilter
diff --git a/src/hooks/index.js b/src/hooks/index.js
new file mode 100644
index 00000000..7df9cbd4
--- /dev/null
+++ b/src/hooks/index.js
@@ -0,0 +1 @@
+export { useRetrievalServicePoints } from './useRetrievalServicePoints';
diff --git a/src/hooks/useRetrievalServicePoints/index.js b/src/hooks/useRetrievalServicePoints/index.js
new file mode 100644
index 00000000..7532d2aa
--- /dev/null
+++ b/src/hooks/useRetrievalServicePoints/index.js
@@ -0,0 +1 @@
+export { default as useRetrievalServicePoints } from './useRetrievalServicePoints';
diff --git a/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.js b/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.js
new file mode 100644
index 00000000..822f476f
--- /dev/null
+++ b/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.js
@@ -0,0 +1,72 @@
+import { useQuery } from 'react-query';
+
+import {
+ useNamespace,
+ useOkapiKy,
+ useStripes,
+} from '@folio/stripes/core';
+
+import { LOCATIONS_API, SERVICE_POINTS_API } from '../../constants';
+
+const DEFAULT_DATA = [];
+const MAX_RECORDS = 1000;
+
+const useRetrievalServicePoints = (params = {}, options = {}) => {
+ const stripes = useStripes();
+ const [namespace] = useNamespace('locations');
+ const {
+ limit = stripes?.config?.maxUnpagedResourceCount || MAX_RECORDS,
+ query = 'cql.allRecords=1',
+ } = params;
+ const {
+ enabled = true,
+ tenantId,
+ } = options;
+ const ky = useOkapiKy({ tenant: tenantId });
+ const searchParams = { limit, query };
+
+ const {
+ data,
+ isFetched,
+ isFetching,
+ isLoading,
+ } = useQuery(
+ [namespace],
+ async ({ signal }) => {
+ const servicePointsData = await ky.get(SERVICE_POINTS_API, { searchParams })
+ .json()
+ .then(({ servicepoints }) => servicepoints);
+
+ const locationsData = await ky.get(LOCATIONS_API, { searchParams, signal })
+ .json()
+ .then(({ locations }) => locations);
+
+ const retrievalSPs = new Set();
+
+ // primary SP of item's effective location is a retrieval service point
+ // collect the primary service point of each location of a tenant.
+ // prepare the options for retrieval service points filter
+ locationsData.forEach(location => {
+ if (location.primaryServicePoint) retrievalSPs.add(location.primaryServicePoint);
+ });
+
+ const retrievalSPsOptions = servicePointsData
+ .filter(sp => retrievalSPs.has(sp.id))
+ .map(sp => ({ label: sp.name, value: sp.id }));
+
+ return retrievalSPsOptions;
+ },
+ enabled,
+ );
+
+ const retrievalSPsOptions = data?.length ? data : DEFAULT_DATA;
+
+ return {
+ isFetched,
+ isFetching,
+ isLoading,
+ retrievalSPsOptions
+ };
+};
+
+export default useRetrievalServicePoints;
diff --git a/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.test.js b/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.test.js
new file mode 100644
index 00000000..ffb1d322
--- /dev/null
+++ b/src/hooks/useRetrievalServicePoints/useRetrievalServicePoints.test.js
@@ -0,0 +1,80 @@
+import {
+ QueryClient,
+ QueryClientProvider,
+} from 'react-query';
+
+import {
+ renderHook,
+ waitFor,
+} from '@folio/jest-config-stripes/testing-library/react';
+
+import { useOkapiKy } from '@folio/stripes/core';
+
+import useRetrievalServicePoints from './useRetrievalServicePoints';
+import { LOCATIONS_API, SERVICE_POINTS_API } from '../../constants';
+
+const mockTenantId = 'tenantId';
+
+jest.mock('@folio/stripes/core', () => ({
+ ...jest.requireActual('@folio/stripes/core'),
+ useNamespace: jest.fn(() => ['test']),
+ useOkapiKy: jest.fn(),
+ useStripes: jest.fn(() => ({
+ okapi: {
+ tenant: mockTenantId,
+ },
+ })),
+}));
+
+const queryClient = new QueryClient();
+const wrapper = ({ children }) => (
+
+ {children}
+
+);
+
+const retrievalSPsOptions = [
+ {
+ value: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f',
+ label: 'Circ desk 1',
+ },
+ {
+ value: '9d1b77e8-f02e-4b7f-b296-3f2042ddac54',
+ label: 'Circ desk 2',
+ },
+];
+
+const kyResponseMap = {
+ [LOCATIONS_API]: { locations: [
+ { id: '1', primaryServicePoint: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f' },
+ { id: '2', primaryServicePoint: '9d1b77e8-f02e-4b7f-b296-3f2042ddac54' },
+ ] },
+ [SERVICE_POINTS_API]: { servicepoints: [
+ { id: '3a40852d-49fd-4df2-a1f9-6e2641a6e91f', name: 'Circ desk 1' },
+ { id: '9d1b77e8-f02e-4b7f-b296-3f2042ddac54', name: 'Circ desk 2' },
+ { id: '1', name: 'Circ desk 3' },
+ { id: '2', name: 'Circ desk 4' },
+ ] },
+};
+
+describe('useRetrievalServicePoints', () => {
+ const mockUseOkapiKyValue = {
+ get: jest.fn((path) => ({
+ json: () => Promise.resolve(kyResponseMap[path]),
+ })),
+ };
+ const mockUseOkapiKy = useOkapiKy;
+
+ beforeEach(() => {
+ mockUseOkapiKy.mockClear();
+ mockUseOkapiKyValue.get.mockClear();
+ mockUseOkapiKy.mockReturnValue(mockUseOkapiKyValue);
+ });
+
+ it('should fetch retrieval service points', async () => {
+ const { result } = renderHook(() => useRetrievalServicePoints(), { wrapper });
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
+
+ expect(result.current.retrievalSPsOptions).toEqual(retrievalSPsOptions);
+ });
+});
diff --git a/translations/ui-requests/ar.json b/translations/ui-requests/ar.json
index 3f284be0..7bc25f44 100644
--- a/translations/ui-requests/ar.json
+++ b/translations/ui-requests/ar.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ber.json b/translations/ui-requests/ber.json
index edc5f986..96988853 100644
--- a/translations/ui-requests/ber.json
+++ b/translations/ui-requests/ber.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ca.json b/translations/ui-requests/ca.json
index 2b8ff5b8..8b745e68 100644
--- a/translations/ui-requests/ca.json
+++ b/translations/ui-requests/ca.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/cs_CZ.json b/translations/ui-requests/cs_CZ.json
index f6a7b6ca..10d998aa 100644
--- a/translations/ui-requests/cs_CZ.json
+++ b/translations/ui-requests/cs_CZ.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Nevytištěno",
"printDetails.printCount": "# Kopie",
"permission.moveRequest.execute": "Požadavky: Přejít na novou jednotku, změnit pořadí fronty",
- "permission.reorderQueue.execute": "Žádanky: Změna pořadí ve frontě"
+ "permission.reorderQueue.execute": "Žádanky: Změna pořadí ve frontě",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/da.json b/translations/ui-requests/da.json
index efe02a48..4279450e 100644
--- a/translations/ui-requests/da.json
+++ b/translations/ui-requests/da.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/de.json b/translations/ui-requests/de.json
index 9a38daa3..bb59f9d8 100644
--- a/translations/ui-requests/de.json
+++ b/translations/ui-requests/de.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Nicht gedruckt",
"printDetails.printCount": "# Exemplare",
"permission.moveRequest.execute": "Bestandsanfragen: Verschieben zu neuem Exemplar, Warteliste neu anordnen",
- "permission.reorderQueue.execute": "Bestandsanfragen: Warteliste neu anordnen"
+ "permission.reorderQueue.execute": "Bestandsanfragen: Warteliste neu anordnen",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/en_GB.json b/translations/ui-requests/en_GB.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/en_GB.json
+++ b/translations/ui-requests/en_GB.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/en_SE.json b/translations/ui-requests/en_SE.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/en_SE.json
+++ b/translations/ui-requests/en_SE.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/en_US.json b/translations/ui-requests/en_US.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/en_US.json
+++ b/translations/ui-requests/en_US.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/es.json b/translations/ui-requests/es.json
index e393b91d..8b961b4e 100644
--- a/translations/ui-requests/es.json
+++ b/translations/ui-requests/es.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/es_419.json b/translations/ui-requests/es_419.json
index e393b91d..8b961b4e 100644
--- a/translations/ui-requests/es_419.json
+++ b/translations/ui-requests/es_419.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/es_ES.json b/translations/ui-requests/es_ES.json
index e393b91d..8b961b4e 100644
--- a/translations/ui-requests/es_ES.json
+++ b/translations/ui-requests/es_ES.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/fr.json b/translations/ui-requests/fr.json
index 2b8ff5b8..8b745e68 100644
--- a/translations/ui-requests/fr.json
+++ b/translations/ui-requests/fr.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/fr_FR.json b/translations/ui-requests/fr_FR.json
index 18e9032e..3f1f8261 100644
--- a/translations/ui-requests/fr_FR.json
+++ b/translations/ui-requests/fr_FR.json
@@ -225,7 +225,7 @@
"duplicateRequest.success": "La réservation a été créée avec succès pour {requester}",
"duplicateRequest.fail": "This request was not placed successfully",
"requests": "{number} réservations",
- "item.status.agedToLost": "Aged to lost",
+ "item.status.agedToLost": "Considéré comme perdu",
"item.status.available": "Disponible",
"item.status.awaitingDelivery": "En attente de livraison",
"item.status.awaitingPickup": "En attente de retrait",
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/he.json b/translations/ui-requests/he.json
index 2b8ff5b8..8b745e68 100644
--- a/translations/ui-requests/he.json
+++ b/translations/ui-requests/he.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/hi_IN.json b/translations/ui-requests/hi_IN.json
index 2b8ff5b8..8b745e68 100644
--- a/translations/ui-requests/hi_IN.json
+++ b/translations/ui-requests/hi_IN.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/hu.json b/translations/ui-requests/hu.json
index 19b2c628..42d89c98 100644
--- a/translations/ui-requests/hu.json
+++ b/translations/ui-requests/hu.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/it_IT.json b/translations/ui-requests/it_IT.json
index 464bbbb3..c9187415 100644
--- a/translations/ui-requests/it_IT.json
+++ b/translations/ui-requests/it_IT.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ja.json b/translations/ui-requests/ja.json
index a34aaf33..24373e50 100644
--- a/translations/ui-requests/ja.json
+++ b/translations/ui-requests/ja.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ko.json b/translations/ui-requests/ko.json
index 0a44c13d..c2b4629a 100644
--- a/translations/ui-requests/ko.json
+++ b/translations/ui-requests/ko.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/nb.json b/translations/ui-requests/nb.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/nb.json
+++ b/translations/ui-requests/nb.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/nl.json b/translations/ui-requests/nl.json
index 8fc18fc5..ef2da0eb 100644
--- a/translations/ui-requests/nl.json
+++ b/translations/ui-requests/nl.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Niet afgedrukt",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Ophaalservicepunt",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/nn.json b/translations/ui-requests/nn.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/nn.json
+++ b/translations/ui-requests/nn.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/pl.json b/translations/ui-requests/pl.json
index 4bed57a3..16819c68 100644
--- a/translations/ui-requests/pl.json
+++ b/translations/ui-requests/pl.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/pt_BR.json b/translations/ui-requests/pt_BR.json
index 0d5a2a79..c19e709a 100644
--- a/translations/ui-requests/pt_BR.json
+++ b/translations/ui-requests/pt_BR.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Não impresso",
"printDetails.printCount": "# Cópias",
"permission.moveRequest.execute": "Requisições: Mover para novo item, reordenar fila",
- "permission.reorderQueue.execute": "Requisições: Reordenar fila"
+ "permission.reorderQueue.execute": "Requisições: Reordenar fila",
+ "requests.retrievalServicePoint": "Ponto de serviço de recuperação",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/pt_PT.json b/translations/ui-requests/pt_PT.json
index cca24cde..fde0aa94 100644
--- a/translations/ui-requests/pt_PT.json
+++ b/translations/ui-requests/pt_PT.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ru.json b/translations/ui-requests/ru.json
index e8c98aeb..f78c9493 100644
--- a/translations/ui-requests/ru.json
+++ b/translations/ui-requests/ru.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/sk.json b/translations/ui-requests/sk.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/sk.json
+++ b/translations/ui-requests/sk.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/sv.json b/translations/ui-requests/sv.json
index de6167ac..40029e84 100644
--- a/translations/ui-requests/sv.json
+++ b/translations/ui-requests/sv.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/ur.json b/translations/ui-requests/ur.json
index 47b69003..e335081b 100644
--- a/translations/ui-requests/ur.json
+++ b/translations/ui-requests/ur.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/zh_CN.json b/translations/ui-requests/zh_CN.json
index dec320b4..0251bf79 100644
--- a/translations/ui-requests/zh_CN.json
+++ b/translations/ui-requests/zh_CN.json
@@ -298,6 +298,8 @@
"filters.printStatus.printed": "已打印",
"filters.printStatus.notPrinted": "未打印",
"printDetails.printCount": "# 份数",
- "permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.moveRequest.execute": "请求:移至新单件,重新排序队列",
+ "permission.reorderQueue.execute": "请求:重新排序队列",
+ "requests.retrievalServicePoint": "检索服务点",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file
diff --git a/translations/ui-requests/zh_TW.json b/translations/ui-requests/zh_TW.json
index b3bf63e2..61e752e6 100644
--- a/translations/ui-requests/zh_TW.json
+++ b/translations/ui-requests/zh_TW.json
@@ -299,5 +299,7 @@
"filters.printStatus.notPrinted": "Not printed",
"printDetails.printCount": "# Copies",
"permission.moveRequest.execute": "Requests: Move to new item, reorder queue",
- "permission.reorderQueue.execute": "Requests: Reorder queue"
+ "permission.reorderQueue.execute": "Requests: Reorder queue",
+ "requests.retrievalServicePoint": "Retrieval service point",
+ "retrievalServicePoint.name": "Retrieval service point"
}
\ No newline at end of file