Skip to content

Commit

Permalink
UIIN-2452: Enable/disable consortial holdings/item actions based on U…
Browse files Browse the repository at this point in the history
…ser permissions (#2284)

* Consortial holdings acc

* UIIN-2410: Adjustments

* UIIN-2410: Add new hook

* UIIN-2410: Add tests

* UIIN-2452: Disable buttons when member tenant does not have permissions

* UIIN-2410: Instance 3rd pane: Add consortial holdings/item accordion

* UIIN-2452: Add unit tests & switching affiliation when view holdings and add item

* UIIN-2410: Fix tests

* UIIN-2452: Add switching affiliation when click on item barcode & Add holdings button

* UIIN-2452: Fix tests

* Update HoldingAccordion.js

* Update HoldingButtonsGroup.js

* UIIN-2452: Fix tests

* Update HoldingsListMovement.js

* Update HoldingContainer.js

* UIIN-2452: Add returning to the previous affiliation

* UIIN-2452: Add tenantId to props validation

* UIIN-2452: Add behaviour for non-consortial tenant

* Fix some comments

* Fix perms handling

* Fix warnings

* Adjust tests

* Fix tests

* UIIN-2452: Switch user affiliation using validateUser

* Update HoldingAccordion.js

* Supress Add holding & Add item & View holdings buttons if user doesn't have permissions

* UIIN-2452: Fix comments & add unit tests

* UIIN-2452: Fixes after review

* UIIN-2452: Fix code smells

---------

Co-authored-by: Mariia_Aloshyna <[email protected]>
Co-authored-by: Mariia Aloshyna <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2023
1 parent 306b510 commit 90f2bff
Show file tree
Hide file tree
Showing 41 changed files with 671 additions and 143 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* If Shared & Held by facets were selected in the Browse search, then retain them in the Search lookup after clicking the record. Refs UIIN-2608.
* Instance. Series heading has vanished in detailed view. Fixes UIIN-2601.
* Remove error message after switch from Instance Edit screen to another app. Fixes UIIN-2600.
* Enable/disable consortial holdings/item actions based on User permissions. Refs UIIN-2452.

## [10.0.0](https://github.com/folio-org/ui-inventory/tree/v10.0.0) (2023-10-13)
[Full Changelog](https://github.com/folio-org/ui-inventory/compare/v9.4.12...v10.0.0)
Expand Down
13 changes: 8 additions & 5 deletions src/Holding/CreateHolding/CreateHolding.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ import {
stripesConnect,
stripesShape,
} from '@folio/stripes/core';
import {
LoadingView,
} from '@folio/stripes/components';
import { LoadingView } from '@folio/stripes/components';

import {
useInstance,
} from '../../common/hooks';
import useCallout from '../../hooks/useCallout';
import HoldingsForm from '../../edit/holdings/HoldingsForm';
import { switchAffiliation } from '../../utils';

const CreateHolding = ({
history,
Expand All @@ -31,14 +30,19 @@ const CreateHolding = ({
const callout = useCallout();
const { instance, isLoading: isInstanceLoading } = useInstance(instanceId);
const sourceId = referenceData.holdingsSourcesByName?.FOLIO?.id;
const { location: { state: { tenantFrom } } } = history;

const onCancel = useCallback(() => {
const goBack = useCallback(() => {
history.push({
pathname: `/inventory/view/${instanceId}`,
search: location.search,
});
}, [location.search, instanceId]);

const onCancel = useCallback(() => {
switchAffiliation(stripes, tenantFrom, goBack);
}, [stripes, tenantFrom, goBack]);

const onSubmit = useCallback((newHolding) => {
return mutator.holding.POST(newHolding)
.then((holdingsRecord) => {
Expand Down Expand Up @@ -93,7 +97,6 @@ CreateHolding.manifest = Object.freeze({
CreateHolding.propTypes = {
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,

instanceId: PropTypes.string.isRequired,
mutator: PropTypes.object.isRequired,
referenceData: PropTypes.object.isRequired,
Expand Down
8 changes: 6 additions & 2 deletions src/Holding/ViewHolding/HoldingBoundWith/HoldingBoundWith.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ import {
MultiColumnList,
} from '@folio/stripes/components';

import { IntlConsumer } from '@folio/stripes/core';
import {
IntlConsumer,
useStripes,
} from '@folio/stripes/core';
import { noValue } from '../../../constants';
import { checkIfArrayIsEmpty } from '../../../utils';
import useBoundWithItems from './useBoundWithItems';
import useBoundWithHoldings from './useBoundWithHoldings';

const HoldingBoundWith = ({ boundWithParts }) => {
const { okapi: { tenant: tenantId } } = useStripes();
const { boundWithItems } = useBoundWithItems(boundWithParts);
const { isLoading, boundWithHoldings } = useBoundWithHoldings(boundWithItems);
const { isLoading, boundWithHoldings } = useBoundWithHoldings(boundWithItems, tenantId);
const boundWithHoldingsMapById = keyBy(boundWithHoldings, 'id');
const data = boundWithItems?.map(boundWithItem => ({
item: boundWithItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import useChunkedCQLFetch from '../../../hooks/useChunkedCQLFetch';

const useBoundWithHoldings = (boundWithItems) => {
const useBoundWithHoldings = (boundWithItems, tenantId) => {
let holdingsRecordIds = boundWithItems?.map(x => x.holdingsRecordId);

// De-dup the list of holdingsRecordIds for efficiency
Expand All @@ -13,7 +13,8 @@ const useBoundWithHoldings = (boundWithItems) => {
holdingQueries.reduce((acc, curr) => {
return [...acc, ...(curr?.data?.holdingsRecords ?? [])];
}, [])
)
),
tenantId,
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import { renderHook, act } from '@folio/jest-config-stripes/testing-library/reac

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

import { useOkapiKy } from '@folio/stripes/core';

import { boundWithHoldingsRecords } from './fixtures';
import useBoundWithHoldings from './useBoundWithHoldings';
import { useTenantKy } from '../../../common';

jest.mock('../../../common', () => ({
...jest.requireActual('../../../common'),
useTenantKy: jest.fn(),
}));

const queryClient = new QueryClient();
const wrapper = ({ children }) => (
Expand All @@ -21,7 +25,7 @@ const wrapper = ({ children }) => (

describe('useBoundWithHoldings', () => {
beforeEach(() => {
useOkapiKy.mockClear().mockReturnValue({
useTenantKy.mockClear().mockReturnValue({
get: () => ({
json: () => Promise.resolve({ holdingsRecords: boundWithHoldingsRecords }),
}),
Expand All @@ -31,15 +35,15 @@ describe('useBoundWithHoldings', () => {
it('should fetch bound-with holdings', async () => {
const boundWithItems = [{ hrid: 'BW-ITEM-1', holdingsRecordId: '9e8dc8ce-68f3-4e75-8479-d548ce521157' }];

const { result } = renderHook(() => useBoundWithHoldings(boundWithItems), { wrapper });
const { result } = renderHook(() => useBoundWithHoldings(boundWithItems, 'testTenantId'), { wrapper });

await act(() => !result.current.isLoading);

expect(result.current.boundWithHoldings).toEqual(boundWithHoldingsRecords);
});

it('should not fetch bound-with holdings', async () => {
const { result } = renderHook(() => useBoundWithHoldings([]), { wrapper });
const { result } = renderHook(() => useBoundWithHoldings([], 'testTenantId'), { wrapper });

expect(result.current.isLoading).toBe(false);
expect(result.current.boundWithHoldings).toEqual([]);
Expand Down
14 changes: 13 additions & 1 deletion src/Instance/HoldingsList/Holding/Holding.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { FormattedMessage } from 'react-intl';

import { Checkbox } from '@folio/stripes/components';

import { ItemsListContainer, DropZone } from '../../ItemsList';
import {
ItemsListContainer,
DropZone,
} from '../../ItemsList';

import HoldingAccordion from './HoldingAccordion';

Expand All @@ -20,6 +23,9 @@ const Holding = ({
isDraggable,
isItemsDroppable,
tenantId,
showViewHoldingsButton,
showAddItemButton,
isBarcodeAsHotlink,
instanceId,
pathToAccordionsState,
}) => {
Expand Down Expand Up @@ -53,12 +59,15 @@ const Holding = ({
tenantId={tenantId}
instanceId={instanceId}
pathToAccordionsState={pathToAccordionsState}
showViewHoldingsButton={showViewHoldingsButton}
showAddItemButton={showAddItemButton}
>
<ItemsListContainer
holding={holding}
draggable={draggable}
droppable={droppable}
tenantId={tenantId}
isBarcodeAsHotlink={isBarcodeAsHotlink}
/>
</HoldingAccordion>
</DropZone>
Expand All @@ -79,6 +88,9 @@ Holding.propTypes = {
isHoldingDragSelected: PropTypes.func,
isItemsDroppable: PropTypes.bool,
tenantId: PropTypes.string,
showViewHoldingsButton: PropTypes.bool,
showAddItemButton: PropTypes.bool,
isBarcodeAsHotlink: PropTypes.bool,
pathToAccordionsState: PropTypes.arrayOf(PropTypes.string),
};

Expand Down
10 changes: 9 additions & 1 deletion src/Instance/HoldingsList/Holding/HoldingAccordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import {
} from '@folio/stripes/components';

import { callNumberLabel } from '../../../utils';

import HoldingButtonsGroup from './HoldingButtonsGroup';
import useHoldingItemsQuery from '../../../hooks/useHoldingItemsQuery';
import {
useHoldingsAccordionState,
useLocationsQuery,
useHoldingItemsQuery,
} from '../../../hooks';

const HoldingAccordion = ({
Expand All @@ -26,6 +27,8 @@ const HoldingAccordion = ({
onAddItem,
withMoveDropdown,
tenantId,
showViewHoldingsButton,
showAddItemButton,
instanceId,
pathToAccordionsState,
}) => {
Expand Down Expand Up @@ -63,6 +66,9 @@ const HoldingAccordion = ({
onAddItem={onAddItem}
withMoveDropdown={withMoveDropdown}
isOpen={open}
tenantId={tenantId}
showViewHoldingsButton={showViewHoldingsButton}
showAddItemButton={showAddItemButton}
/>;

const location = labelLocation?.isActive ?
Expand Down Expand Up @@ -125,6 +131,8 @@ HoldingAccordion.propTypes = {
children: PropTypes.object,
tenantId: PropTypes.string,
pathToAccordionsState: PropTypes.arrayOf(PropTypes.string),
showViewHoldingsButton: PropTypes.bool,
showAddItemButton: PropTypes.bool,
};

HoldingAccordion.defaultProps = { pathToAccordionsState: [] };
Expand Down
6 changes: 4 additions & 2 deletions src/Instance/HoldingsList/Holding/HoldingAccordion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import '../../../../test/jest/__mock__';
import renderWithIntl from '../../../../test/jest/helpers/renderWithIntl';
import translations from '../../../../test/jest/helpers/translationsProperties';
import { items as itemsFixture } from '../../../../test/fixtures/items';
import { useHoldingItemsQuery } from '../../../hooks';

import HoldingAccordion from './HoldingAccordion';
import useHoldingItemsQuery from '../../../hooks/useHoldingItemsQuery';

jest.mock('../../../hooks/useHoldingItemsQuery', () => jest.fn());
jest.mock('../../../hooks', () => ({
Expand All @@ -23,7 +24,8 @@ jest.mock('../../../hooks', () => ({
isActive: false,
},
],
})
}),
useHoldingItemsQuery: jest.fn(),
}));

const HoldingAccordionSetup = () => (
Expand Down
30 changes: 19 additions & 11 deletions src/Instance/HoldingsList/Holding/HoldingButtonsGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
Icon,
} from '@folio/stripes/components';

import { switchAffiliation } from '../../../utils';

import { MoveToDropdown } from './MoveToDropdown';

const HoldingButtonsGroup = ({
Expand All @@ -24,6 +26,9 @@ const HoldingButtonsGroup = ({
onAddItem,
itemCount,
isOpen,
tenantId,
showViewHoldingsButton,
showAddItemButton,
}) => {
const stripes = useStripes();
const isUserInCentralTenant = checkIfUserInCentralTenant(stripes);
Expand All @@ -39,20 +44,21 @@ const HoldingButtonsGroup = ({
/>
)
}
<Button
id={`clickable-view-holdings-${holding.id}`}
data-test-view-holdings
onClick={onViewHolding}
>
<FormattedMessage id="ui-inventory.viewHoldings" />
</Button>

{!isUserInCentralTenant && (
{showViewHoldingsButton &&
<Button
id={`clickable-view-holdings-${holding.id}`}
data-test-view-holdings
onClick={() => switchAffiliation(stripes, tenantId, onViewHolding)}
>
<FormattedMessage id="ui-inventory.viewHoldings" />
</Button>
}
{!isUserInCentralTenant && showAddItemButton && (
<IfPermission perm="ui-inventory.item.create">
<Button
id={`clickable-new-item-${holding.id}`}
data-test-add-item
onClick={onAddItem}
onClick={() => switchAffiliation(stripes, tenantId, onAddItem)}
buttonStyle="primary paneHeaderNewButton"
>
<FormattedMessage id="ui-inventory.addItem" />
Expand All @@ -73,7 +79,9 @@ HoldingButtonsGroup.propTypes = {
onAddItem: PropTypes.func.isRequired,
onViewHolding: PropTypes.func.isRequired,
withMoveDropdown: PropTypes.bool,
showViewHoldingsButton: PropTypes.bool,
showAddItemButton: PropTypes.bool,
tenantId: PropTypes.string,
};


export default memo(HoldingButtonsGroup);
Loading

0 comments on commit 90f2bff

Please sign in to comment.