Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into UIIN-2896
Browse files Browse the repository at this point in the history
  • Loading branch information
BogdanDenis committed May 14, 2024
2 parents 9746637 + e0bc47e commit c4a4066
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* Use consolidated locations endpoint to fetch all locations when in central tenant context. Refs UIIN-2811.
* Change label of eye-readable call number search option in holdings/items. Refs UIIN-2797.
* Jest/RTL: Cover ModalContent components with unit tests. Refs UIIN-2669.
* Add callout noting user's active affiliation when it changes after selecting holding or item. Refs UIIN-2831, UIIN-2872.
* Jest/RTL: Cover LocationSelectionWithCheck components with unit tests. Refs UIIN-2670.
* Inventory app: Define and implement shortcut key for editing a quickMARC bib record. Refs UIIN-2896.

## [11.0.4](https://github.com/folio-org/ui-inventory/tree/v11.0.4) (2024-04-30)
Expand Down
10 changes: 9 additions & 1 deletion src/Instance/HoldingsList/Holding/HoldingContainer.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import React, {
useCallback,
useMemo,
useContext,
} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import { Draggable } from 'react-beautiful-dnd';
import { FormattedMessage } from 'react-intl';

import { useStripes } from '@folio/stripes/core';
import {
useStripes,
CalloutContext,
} from '@folio/stripes/core';

import Holding from './Holding';
import {
navigateToHoldingsViewPage,
navigateToItemCreatePage,
} from '../../utils';
import { sendCalloutOnAffiliationChange } from '../../../utils';

const dragStyles = {
background: '#333',
Expand Down Expand Up @@ -128,9 +133,12 @@ const HoldingContainer = ({
...rest
}) => {
const stripes = useStripes();
const callout = useContext(CalloutContext);

const onViewHolding = useCallback(() => {
navigateToHoldingsViewPage(history, location, instance, holding, tenantId, stripes.okapi.tenant);

sendCalloutOnAffiliationChange(stripes, tenantId, callout);
}, [location.search, instance.id, holding.id]);

const onAddItem = useCallback(() => {
Expand Down
9 changes: 7 additions & 2 deletions src/Instance/ItemsList/ItemBarcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import {
} from '@folio/stripes/components';
import css from '../../View.css';
import { QUERY_INDEXES } from '../../constants';
import { switchAffiliation } from '../../utils';
import {
switchAffiliation,
sendCalloutOnAffiliationChange,
} from '../../utils';

const ItemBarcode = ({
location,
Expand All @@ -33,6 +36,7 @@ const ItemBarcode = ({
}) => {
const history = useHistory();
const stripes = useStripes();
const callout = useContext(CalloutContext);
const { search } = location;
const queryBarcode = queryString.parse(search)?.query;
const isQueryByBarcode = queryString.parse(search)?.qindex === QUERY_INDEXES.BARCODE;
Expand All @@ -46,9 +50,10 @@ const ItemBarcode = ({
tenantFrom: stripes.okapi.tenant,
},
});

sendCalloutOnAffiliationChange(stripes, tenantId, callout);
}, [instanceId, holdingId, item.id, search]);

const callout = useContext(CalloutContext);
const onCopyToClipbaord = useCallback(() => {
callout.sendCallout({
type: 'success',
Expand Down
97 changes: 97 additions & 0 deletions src/edit/common/LocationSelectionWithCheck.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';

import {
screen,
act,
} from '@folio/jest-config-stripes/testing-library/react';
import { fireEvent } from '@folio/jest-config-stripes/testing-library/dom';

import '../../../test/jest/__mock__';
import { LocationSelectionWithCheck } from './LocationSelectionWithCheck';
import { renderWithFinalForm, renderWithIntl } from '../../../test/jest/helpers';
import renderWithRouter from '../../../test/jest/helpers/renderWithRouter';

jest.mock('../../RemoteStorageService', () => ({
Check: {
useByLocation: jest.fn(() => jest.fn(() => true)), // Mocking always true for check
},
Confirmation: {
Heading: jest.fn(() => 'Remote Storage Heading'),
Message: jest.fn(() => 'Remote Storage Message'),
},
}));

jest.mock('@folio/stripes/smart-components', () => (
{ ...jest.requireActual('@folio/stripes/smart-components'),
LocationSelection: (props) => {
const { onSelect, resources } = props;
return (
<button
type="button"
data-testid="selection-id"
onClick={() => onSelect(resources.locations.records)}
>
LocationSelection
</button>
);
} }));

const inputMock = {
value: 'test',
onChange: jest.fn(),
};

const restMock = {
meta: {
initial: 1
},
resources: {
'id': '2b51c2f5-6779-4913-9cc8-05508ea406a4',
'isPrimary': false,
'tenantId': 'diku',
'tenantName': 'Snapshot',
'userId': 'f2a0e0ce-cef9-51e5-979a-7cea9db21ecf',
'username': 'diku_admin',
locations: {
records:
{
name: 'Test Location',
id: '2',
code: '1',
isActive: true,
}
}
},
};

describe('LocationSelectionWithCheck', () => {
afterEach(() => {
jest.clearAllMocks();
});

it('render with selected location and confirm changes', async () => {
renderWithIntl(renderWithRouter(renderWithFinalForm(
<LocationSelectionWithCheck name="location" input={inputMock} {...restMock} />
)));

const confirmButton = screen.getByRole('button', { name: 'confirm' });

act(() => fireEvent.click(screen.getByTestId('selection-id')));

fireEvent.click(confirmButton);
expect(inputMock.onChange).toHaveBeenCalled();
});

it('render with selected location and cancel changes', async () => {
renderWithIntl(renderWithRouter(renderWithFinalForm(
<LocationSelectionWithCheck name="location" input={inputMock} {...restMock} />
)));

const cancelButton = screen.getByRole('button', { name: 'cancel' });

act(() => fireEvent.click(screen.getByTestId('selection-id')));

fireEvent.click(cancelButton);
expect(inputMock.onChange).not.toHaveBeenCalled();
});
});
23 changes: 23 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -930,3 +930,26 @@ export const redirectToMarcEditPage = (pathname, instance, location, history) =>
search: searchParams.toString(),
});
};

export const sendCalloutOnAffiliationChange = (stripes, tenantId, callout) => {
if (tenantId && stripes.okapi.tenant !== tenantId) {
const name = stripes.user.user.tenants.find(tenant => tenant.id === tenantId)?.name;

if (name) {
callout.sendCallout({
type: 'info',
message: (
<FormattedMessage
id="ui-inventory.affiliationChanging.namedNotification"
values={{ name }}
/>
),
});
} else {
callout.sendCallout({
type: 'info',
message: <FormattedMessage id="ui-inventory.affiliationChanging.notification" />,
});
}
}
};
85 changes: 85 additions & 0 deletions src/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
setRecordForDeletion,
parseEmptyFormValue,
redirectToMarcEditPage,
sendCalloutOnAffiliationChange,
} from './utils';
import {
CONTENT_TYPE_HEADER,
Expand Down Expand Up @@ -301,3 +302,87 @@ describe('redirectToMarcEditPage', () => {
});
});
});

describe('sendCalloutOnAffiliationChange', () => {
const callout = {
sendCallout: jest.fn(),
};
const tenantId = 'tenantId';

afterEach(() => {
jest.clearAllMocks();
});

describe('When tenant changed', () => {
const okapi = {
tenant: 'okapiTenantId',
};

it('should send named informational notification callout', () => {
const stripes = {
user: {
user: {
tenants: [
{
id: tenantId,
name: 'name',
}
],
},
},
okapi,
};
const expectedArgs = {
type: 'info',
message: (
<FormattedMessage
id="ui-inventory.affiliationChanging.namedNotification"
values={{ name: stripes.user.user.tenants[0].name }}
/>
),
};

sendCalloutOnAffiliationChange(stripes, tenantId, callout);

expect(callout.sendCallout).toHaveBeenCalledWith(expect.objectContaining(expectedArgs));
});

it('should send general informational notification callout', () => {
const stripes = {
user: {
user: {
tenants: [],
},
},
okapi,
};
const expectedArgs = {
type: 'info',
message: <FormattedMessage id="ui-inventory.affiliationChanging.notification" />,
};

sendCalloutOnAffiliationChange(stripes, tenantId, callout);

expect(callout.sendCallout).toHaveBeenCalledWith(expect.objectContaining(expectedArgs));
});
});

describe('When tenant is not changed', () => {
it('should not trigger callout', () => {
const stripes = {
user: {
user: {
tenants: [],
},
},
okapi: {
tenant: tenantId,
},
};

sendCalloutOnAffiliationChange(stripes, tenantId, callout);

expect(callout.sendCallout).not.toHaveBeenCalled();
});
});
});
2 changes: 2 additions & 0 deletions translations/ui-inventory/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@
"marc": "MARC",
"unknownNoteType": "Unknown note type",
"communicationProblem": "Server communication problem. Please try again",
"affiliationChanging.notification": "Active affiliation has changed",
"affiliationChanging.namedNotification": "Active affiliation has changed to {name}",
"item.status": "Item status",
"item.status.agedToLost": "Aged to lost",
"item.status.available": "Available",
Expand Down

0 comments on commit c4a4066

Please sign in to comment.