Skip to content

Commit

Permalink
UIIN-1970: Show inactive locations on instance view (folio-org#1845)
Browse files Browse the repository at this point in the history
Co-authored-by: Michal Kuklis <[email protected]>
  • Loading branch information
maccabeelevine and mkuklis authored Nov 28, 2022
1 parent 7c04855 commit 565144a
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Browse refactor: Show instance result in third pane when Number of titles = `1`. Refs UIIN-2186.
* Optimistic locking error appears when user adds more than 1 tag to "Holdings" record. Fixes UIIN-2242.
* Fix holdings view bound-with table also displaying directly linked items. Fixes UIIN-2260.
* Display "Inactive" by inactive locations on instance view. Fixes UIIN-1970.

## [9.2.0](https://github.com/folio-org/ui-inventory/tree/v9.2.0) (2022-10-27)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v9.1.0...v9.2.0)
Expand Down
14 changes: 12 additions & 2 deletions src/Instance/HoldingsList/Holding/HoldingAccordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ const HoldingAccordion = ({
};

const { locationsById } = useContext(DataContext);
const labelLocation = locationsById[holding.permanentLocationId]?.name ?? '';
const labelLocation = locationsById[holding.permanentLocationId];
const labelLocationName = labelLocation?.name ?? '';
const [open, setOpen] = useState(false);
const [openFirstTime, setOpenFirstTime] = useState(false);
const { totalRecords, isFetching } = useHoldingItemsQuery(holding.id, { searchParams, key: 'itemCount' });
Expand All @@ -54,6 +55,15 @@ const HoldingAccordion = ({
isOpen={open}
/>;

const location = labelLocation?.isActive ?
labelLocationName :
<FormattedMessage
id="ui-inventory.inactive.paneTitle"
values={{
location: labelLocationName,
}}
/>;

return (
<Accordion
id={holding.id}
Expand All @@ -64,7 +74,7 @@ const HoldingAccordion = ({
<FormattedMessage
id="ui-inventory.holdingsHeader"
values={{
location: labelLocation,
location,
callNumber: callNumberLabel(holding),
copyNumber: holding.copyNumber,
}}
Expand Down
23 changes: 20 additions & 3 deletions src/Instance/HoldingsList/Holding/HoldingAccordion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { noop } from 'lodash';
import userEvent from '@testing-library/user-event';
import { act } from 'react-dom/test-utils';
import { screen } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';

import '../../../../test/jest/__mock__';

Expand All @@ -21,13 +21,23 @@ const HoldingAccordionSetup = () => (
<Router>
<DataContext.Provider value={{ locationsById: {} }}>
<HoldingAccordion
holding={{ id: '123' }}
holding={{
id: '123',
permanentLocation: { id: 'inactiveLocation' },
}}
holdings={[]}
locationsById={[
{
id: 'inactiveLocation',
name: 'Location 1',
isActive: false,
},
]}
onViewHolding={noop}
onAddItem={noop}
withMoveDropdown={false}
>
{() => null}
<></>
</HoldingAccordion>
</DataContext.Provider>
</Router>
Expand All @@ -49,6 +59,13 @@ describe('HoldingAccordion', () => {
jest.clearAllMocks();
});

it('should display "inactive" if applicable in the accordion header', async () => {
await waitFor(() => {
const accordionSection = document.querySelector('*[data-test-accordion-section=true]').innerHTML;
expect(accordionSection).toContain('Inactive');
});
});

it('should render items counter', () => {
expect(screen.getByText('3')).toBeInTheDocument();
});
Expand Down
18 changes: 16 additions & 2 deletions src/Instance/ItemsList/ItemsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {
useCallback,
useState,
useEffect,
useContext,
} from 'react';
import PropTypes from 'prop-types';
import {
Expand All @@ -27,8 +28,12 @@ import {
} from './utils';
import useBoundWithHoldings from '../../Holding/ViewHolding/HoldingBoundWith/useBoundWithHoldings';

import { DataContext } from '../../contexts';

const getTableAria = (intl) => intl.formatMessage({ id: 'ui-inventory.items' });
const getFormatter = (
intl,
locationsById,
holding,
holdingsMapById,
selectItemsForDrag,
Expand Down Expand Up @@ -81,7 +86,15 @@ const getFormatter = (
'copyNumber': ({ copyNumber }) => copyNumber || noValue,
'materialType': x => x.materialType?.name || noValue,
'loanType': x => x.temporaryLoanType?.name || x.permanentLoanType?.name || noValue,
'effectiveLocation': x => x.effectiveLocation?.name || noValue,
'effectiveLocation': x => {
const effectiveLocation = locationsById[x.effectiveLocation?.id];
return effectiveLocation?.isActive ?
effectiveLocation?.name || noValue :
intl.formatMessage(
{ id: 'ui-inventory.inactive.gridCell' },
{ location: effectiveLocation?.name }
);
},
'enumeration': x => x.enumeration || noValue,
'chronology': x => x.chronology || noValue,
'volume': x => x.volume || noValue,
Expand Down Expand Up @@ -145,14 +158,15 @@ const ItemsList = ({
});
const [records, setRecords] = useState([]);
const [paginatedItems, setPaginatedItems] = useState([]);
const { locationsById } = useContext(DataContext);

const ariaLabel = useMemo(() => getTableAria(intl), []);
const columnMapping = useMemo(
() => getColumnMapping(intl, holding.id, records, isItemsDragSelected, selectItemsForDrag),
[holding.id, records, isItemsDragSelected, selectItemsForDrag],
);
const formatter = useMemo(
() => getFormatter(holding, holdingsMapById, selectItemsForDrag, isItemsDragSelected),
() => getFormatter(intl, locationsById, holding, holdingsMapById, selectItemsForDrag, isItemsDragSelected),
[holding, holdingsMapById, selectItemsForDrag, isItemsDragSelected],
);
const rowProps = useMemo(() => ({
Expand Down
73 changes: 73 additions & 0 deletions src/Instance/ItemsList/tests/ItemsList.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { BrowserRouter as Router } from 'react-router-dom';
import { act } from 'react-dom/test-utils';
import { screen } from '@testing-library/react';

import '../../../../test/jest/__mock__';

import DataContext from '../../../contexts/DataContext';

import { items as itemsFixture } from '../../../../test/fixtures/items';
import { holdingsRecords as holdingsRecordsFixture } from '../../../../test/fixtures/holdingsRecords';
import renderWithIntl from '../../../../test/jest/helpers/renderWithIntl';
import translations from '../../../../test/jest/helpers/translationsProperties';
import ItemsList from '../ItemsList';
import useHoldingItemsQuery from '../../../hooks/useHoldingItemsQuery';

jest.mock('../../../hooks/useHoldingItemsQuery', () => jest.fn());

const queryClient = new QueryClient();

const locations = {
'fcd64ce1-6995-48f0-840e-89ffa2288371':
{
id: 'fcd64ce1-6995-48f0-840e-89ffa2288371',
name: 'Main Library',
isActive: true,
},
'fcd64ce1-6995-48f0-840e-89ffa2288372' :
{
id: 'fcd64ce1-6995-48f0-840e-89ffa2288372',
name: 'Annex',
isActive: false,
},
};

const ItemsListSetup = () => (
<QueryClientProvider client={queryClient}>
<Router>
<DataContext.Provider value={{ locationsById: locations }}>
<ItemsList
items={itemsFixture}
holding={holdingsRecordsFixture[0]}
isItemsDragSelected={(_) => false}
selectItemsForDrag={(_) => {}}
getDraggingItems={jest.fn()}
draggable={false}
/>
</DataContext.Provider>
</Router>
</QueryClientProvider>
);

describe('ItemsList', () => {
beforeEach(async () => {
useHoldingItemsQuery.mockReturnValue({
isFetching: false,
totalRecords: itemsFixture.length,
});

await act(async () => {
await renderWithIntl(<ItemsListSetup />, translations);
});
});

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

it('should display "inactive" by a location if applicable', () => {
expect(screen.queryByText('Inactive')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ModuleHierarchyProvider } from '@folio/stripes-core/src/components/Modu

import '../../../../test/jest/__mock__';
import renderWithIntl from '../../../../test/jest/helpers/renderWithIntl';
import translations from '../../../../test/jest/helpers/translationsProperties';

import InstanceFiltersBrowse from './InstanceFiltersBrowse';

Expand Down Expand Up @@ -64,15 +65,17 @@ const renderInstanceFilters = (props = {}) => {
{...props}
/>
</ModuleHierarchyProvider>
</Router>
</Router>,
translations
);
};

describe('InstanceFilters', () => {
it('Contains a filter for creation date ', () => {
renderInstanceFilters();
const { debug } = renderInstanceFilters();

expect(screen.getByText('ui-inventory.filters.effectiveLocation')).toBeInTheDocument();
debug();
expect(screen.getByText('Effective location (item)')).toBeInTheDocument();
});

describe('When contributors browseType was selected', () => {
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/holdingsRecords.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const holdingsRecords = [
{
id: '44a21d17-a666-4f34-b24d-644f8ed1537b',
}
];
3 changes: 2 additions & 1 deletion test/fixtures/items.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ export const items = [
id: 'fcd64ce1-6995-48f0-840e-89ffa2288371',
name: 'Main Library',
},
}, {
},
{
id: '6abd8dfe-0234-4256-b2e6-539499999cac',
status: {
name: 'Paged',
Expand Down
1 change: 1 addition & 0 deletions test/jest/__mock__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ import './stripesSmartComponents.mock';
import './InstancePlugin.mock';
import './quickMarc.mock';
import './stripesComponents.mock';
import './reactBeautifulDnd.mock';
15 changes: 15 additions & 0 deletions test/jest/__mock__/reactBeautifulDnd.mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
jest.mock('react-beautiful-dnd', () => ({
Droppable: ({ children }) => children({
draggableProps: {
style: {},
},
innerRef: jest.fn(),
}, {}),
Draggable: ({ children }) => children({
draggableProps: {
style: {},
},
innerRef: jest.fn(),
}, {}),
DragDropContext: ({ children }) => children,
}));
10 changes: 10 additions & 0 deletions test/jest/helpers/Harness.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { noop } from 'lodash';
import { IntlProvider } from 'react-intl';
import { CalloutContext } from '@folio/stripes/core';

Expand All @@ -24,12 +25,21 @@ const Harness = ({
mockOffsetSize(width, height);
}

const defaultRichTextElements = ['b', 'i', 'em', 'strong', 'span', 'div', 'p', 'ul', 'ol', 'li', 'code'].reduce((res, Tag) => {
res[Tag] = chunks => <Tag>{chunks}</Tag>;

return res;
}, {});

return (
<CalloutContext.Provider value={{ sendCallout: () => { } }}>
<IntlProvider
locale="en"
key="en"
timeZone="UTC"
onWarn={noop}
onError={noop}
defaultRichTextElements={defaultRichTextElements}
messages={allTranslations}
>
{children}
Expand Down
3 changes: 2 additions & 1 deletion translations/ui-inventory/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
"temporary": "Temporary",
"inactive": "Inactive",
"inactive.paneTitle": "<em>Inactive</em> {location}",
"inactive.gridCell": "<span><em>Inactive</em> {location}</span>",
"selectPermanenLocation": "Select permanent location",
"statisticalCodes": "Statistical codes",
"statisticalCode": "Statistical code",
Expand Down Expand Up @@ -359,7 +360,7 @@
"alternativeTitleType": "Alternative title type",
"materialType": "Material type",
"materialTypeRequired": "Material type *",
"holdingsHeader": "Holdings: {location} > {callNumber} {copyNumber}",
"holdingsHeader": "<span>Holdings: {location} > {callNumber} {copyNumber}</span>",
"holdingsDetails": "Holdings details",
"numberOfItems": "Number of items",
"acquisitions": "Acquisitions",
Expand Down

0 comments on commit 565144a

Please sign in to comment.