From 90a33f42ab732e93da97be9d3a8a715bed0711fa Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Wed, 20 Nov 2024 19:00:06 +0500 Subject: [PATCH] revert: UIREC-393 invalid reference issues due to BE resolves the invalid holding/locations data --- .../PieceForm/PieceFields/PieceFields.js | 3 - src/Piece/PieceForm/PieceForm.js | 36 +-------- src/Piece/PieceForm/PieceFormContainer.js | 17 +++++ .../TitleBindPiecesCreateItemForm.js | 23 +----- src/TitleReceive/TitleReceiveContainer.js | 28 ++----- .../useHoldingsAndLocations.js | 74 +++++++------------ .../useHoldingsAndLocations.test.js | 40 +--------- 7 files changed, 62 insertions(+), 159 deletions(-) diff --git a/src/Piece/PieceForm/PieceFields/PieceFields.js b/src/Piece/PieceForm/PieceFields/PieceFields.js index 043ced35..4f0de777 100644 --- a/src/Piece/PieceForm/PieceFields/PieceFields.js +++ b/src/Piece/PieceForm/PieceFields/PieceFields.js @@ -33,7 +33,6 @@ export const PieceFields = ({ instanceId, locationIds, locations, - isLocationsLoading, pieceFormatOptions, poLine, setLocationValue, @@ -299,7 +298,6 @@ export const PieceFields = ({ disabled={isLocationSelectionDisabled} isNonInteractive={isLocationSelectionDisabled} required={isLocationRequired} - isLoading={isLocationsLoading} /> @@ -314,7 +312,6 @@ PieceFields.propTypes = { label: PropTypes.string, value: PropTypes.string, })), - isLocationsLoading: PropTypes.bool, locationIds: PropTypes.arrayOf(PropTypes.string), locations: PropTypes.arrayOf(PropTypes.object), poLine: PropTypes.object.isRequired, diff --git a/src/Piece/PieceForm/PieceForm.js b/src/Piece/PieceForm/PieceForm.js index 9804b997..51b0c0f2 100644 --- a/src/Piece/PieceForm/PieceForm.js +++ b/src/Piece/PieceForm/PieceForm.js @@ -2,7 +2,6 @@ import PropTypes from 'prop-types'; import { useCallback, useEffect, - useMemo, useRef, } from 'react'; import { FormattedMessage } from 'react-intl'; @@ -33,10 +32,6 @@ import { useModalToggle, } from '@folio/stripes-acq-components'; -import { - useHoldingsAndLocations, - useReceivingTenantIdsAndLocations, -} from '../../common/hooks'; import { getClaimingIntervalFromDate, setLocationValueFormMutator, @@ -68,6 +63,8 @@ const PieceForm = ({ onClose, onDelete: onDeleteProp, onUnreceive: onUnreceiveProp, + locationIds, + locations, paneTitle, pieceFormatOptions, poLine, @@ -95,36 +92,10 @@ const PieceForm = ({ bindItemId, isBound, isCreateItem, - locationId, - holdingId, metadata, receivingStatus, - receivingTenantId, } = formValues; - const receivingTenants = useMemo(() => { - if (poLine?.locations?.length) { - return poLine.locations.map(({ tenantId }) => tenantId); - } - - return []; - }, [poLine?.locations]); - - const receivingTenantIdsAndLocations = useReceivingTenantIdsAndLocations({ - receivingTenantIds: receivingTenants, - currentReceivingTenantId: receivingTenantId, - currentLocationId: locationId, - }); - - const { - locations, - locationIds, - isFetching, - } = useHoldingsAndLocations({ - instanceId, - ...receivingTenantIdsAndLocations, - }); - useEffect(() => { if (!id && format === PIECE_FORMAT.electronic) { batch(() => { @@ -351,7 +322,6 @@ const PieceForm = ({ poLine={poLine} locationIds={locationIds} locations={locations} - isLocationsLoading={isEditMode && (!locationId || !holdingId) && isFetching} setLocationValue={mutators.setLocationValue} onChangeDisplayOnHolding={onChangeDisplayOnHolding} /> @@ -427,6 +397,8 @@ PieceForm.propTypes = { hasValidationErrors: PropTypes.bool.isRequired, initialValues: PropTypes.object.isRequired, instanceId: PropTypes.string, + locationIds: PropTypes.arrayOf(PropTypes.string).isRequired, + locations: PropTypes.arrayOf(PropTypes.object), onClose: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, onUnreceive: PropTypes.func.isRequired, diff --git a/src/Piece/PieceForm/PieceFormContainer.js b/src/Piece/PieceForm/PieceFormContainer.js index a6388a55..44a5b680 100644 --- a/src/Piece/PieceForm/PieceFormContainer.js +++ b/src/Piece/PieceForm/PieceFormContainer.js @@ -18,6 +18,7 @@ import { PIECE_FORMAT, PIECE_FORMAT_OPTIONS, useAcqRestrictions, + useLocationsQuery, useOrderLine, useShowCallout, } from '@folio/stripes-acq-components'; @@ -67,11 +68,17 @@ export const PieceFormContainer = ({ const { targetTenantId: tenantId, + isCentralOrderingEnabled, isCentralRouting, } = useReceivingSearchContext(); /* Data fetching */ + const { + isLoading: isLocationsLoading, + locations, + } = useLocationsQuery({ consortium: isCentralOrderingEnabled }); + const { isLoading: isTitleLoading, title, @@ -115,6 +122,7 @@ export const PieceFormContainer = ({ const canDeletePiece = !(!orderLine?.checkinItems && order?.workflowStatus === ORDER_STATUSES.pending); const instanceId = title?.instanceId; + const pieceLocationId = initialValues?.locationId; const orderFormat = orderLine?.orderFormat; const pieceFormatOptions = orderFormat === ORDER_FORMATS.PEMix ? PIECE_FORMAT_OPTIONS.filter(({ value }) => [PIECE_FORMAT.electronic, PIECE_FORMAT.physical].includes(value)) @@ -122,6 +130,12 @@ export const PieceFormContainer = ({ /* Memoized values */ + const locationIds = useMemo(() => { + const poLineLocationIds = (orderLine?.locations?.map(({ locationId }) => locationId) ?? []).filter(Boolean); + + return (pieceLocationId ? [...new Set([...poLineLocationIds, pieceLocationId])] : poLineLocationIds); + }, [orderLine, pieceLocationId]); + const createInventoryValues = useMemo(() => ({ [PIECE_FORMAT.physical]: orderLine?.physical?.createInventory, [PIECE_FORMAT.electronic]: orderLine?.eresource?.createInventory, @@ -284,6 +298,7 @@ export const PieceFormContainer = ({ const isLoading = ( !initialValues || isLoadingProp + || isLocationsLoading || isTitleLoading || isOrderLineLoading || isOrderLoading @@ -305,6 +320,8 @@ export const PieceFormContainer = ({ onQuickReceive={onQuickReceive} onSubmit={onSubmit} onUnreceive={onUnreceive} + locationIds={locationIds} + locations={locations} paneTitle={paneTitle} pieceFormatOptions={pieceFormatOptions} poLine={orderLine} diff --git a/src/TitleBindPieces/TitleBindPiecesCreateItemForm/TitleBindPiecesCreateItemForm.js b/src/TitleBindPieces/TitleBindPiecesCreateItemForm/TitleBindPiecesCreateItemForm.js index 7540574c..1c8ce11c 100644 --- a/src/TitleBindPieces/TitleBindPiecesCreateItemForm/TitleBindPiecesCreateItemForm.js +++ b/src/TitleBindPieces/TitleBindPiecesCreateItemForm/TitleBindPiecesCreateItemForm.js @@ -18,10 +18,7 @@ import { TextField, } from '@folio/stripes/components'; -import { - useHoldingsAndLocations, - useReceivingTenantIdsAndLocations, -} from '../../common/hooks'; +import { useHoldingsAndLocations } from '../../common/hooks'; import { useReceivingSearchContext } from '../../contexts'; import { PIECE_FORM_FIELD_NAMES } from '../constants'; import { @@ -39,22 +36,9 @@ export const TitleBindPiecesCreateItemForm = ({ const { loanTypes } = useLoanTypes(); const intl = useIntl(); - const { locationId, tenantId: receivingTenantId } = bindItemValues; - - const { - additionalLocationIds, - additionalTenantLocationIdsMap, - tenantId, - } = useReceivingTenantIdsAndLocations({ - currentLocationId: locationId, - currentReceivingTenantId: receivingTenantId, - }); - - const { locations, isFetching } = useHoldingsAndLocations({ + const { locations } = useHoldingsAndLocations({ instanceId, - tenantId, - additionalLocationIds, - additionalTenantLocationIdsMap, + tenantId: bindItemValues.tenantId, }); const { crossTenant } = useReceivingSearchContext(); @@ -155,7 +139,6 @@ export const TitleBindPiecesCreateItemForm = ({ onChange={selectLocation} locationLabelId="ui-receiving.piece.permanentLocationId" holdingLabelId="ui-receiving.piece.permanentLocationId" - isLoading={isFetching} required /> diff --git a/src/TitleReceive/TitleReceiveContainer.js b/src/TitleReceive/TitleReceiveContainer.js index 4d52bd2e..57f12ae2 100644 --- a/src/TitleReceive/TitleReceiveContainer.js +++ b/src/TitleReceive/TitleReceiveContainer.js @@ -12,13 +12,12 @@ import { } from '@folio/stripes/components'; import { PIECE_FORMAT, + useLocationsQuery, useShowCallout, } from '@folio/stripes-acq-components'; import { - useHoldingsAndLocations, useReceive, - useReceivingTenantIdsAndLocations, useTitleHydratedPieces, } from '../common/hooks'; import { @@ -38,6 +37,7 @@ function TitleReceiveContainer({ history, location, match }) { const showCallout = useShowCallout(); const { crossTenant, + isCentralOrderingEnabled, isCentralRouting, targetTenantId, } = useReceivingSearchContext(); @@ -59,24 +59,10 @@ function TitleReceiveContainer({ history, location, match }) { const { receive } = useReceive(); - const receivingTenants = useMemo(() => { - if (pieces?.length) { - return pieces.map(({ receivingTenantId }) => receivingTenantId); - } - - return []; - }, [pieces]); - - const { receivingTenantIds } = useReceivingTenantIdsAndLocations({ - receivingTenantIds: receivingTenants, - currentReceivingTenantId: targetTenantId, - }); - - const { locations, isFetching } = useHoldingsAndLocations({ - instanceId, - receivingTenantIds, - tenantId: targetTenantId, - }); + const { + isLoading: isLocationsLoading, + locations, + } = useLocationsQuery({ consortium: isCentralOrderingEnabled }); const onCancel = useCallback( () => { @@ -136,7 +122,7 @@ function TitleReceiveContainer({ history, location, match }) { [poLine], ); - const isLoading = isPiecesLoading || isFetching; + const isLoading = isPiecesLoading || isLocationsLoading; if (isLoading) { return ( diff --git a/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.js b/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.js index 60670998..148290ed 100644 --- a/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.js +++ b/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.js @@ -1,55 +1,23 @@ import { useQuery } from 'react-query'; -import { LIMIT_MAX } from '@folio/stripes-acq-components'; +import { + batchRequest, + HOLDINGS_API, + LIMIT_MAX, + LOCATIONS_API, +} from '@folio/stripes-acq-components'; import { useNamespace, useOkapiKy, } from '@folio/stripes/core'; -import { - getHoldingLocations, - getHoldingLocationsByTenants, -} from '../../utils/getHoldingLocations'; - const DEFAULT_DATA = []; -export const useHoldingsAndLocations = ({ - instanceId, - options = {}, - tenantId, - /* - `receivingTenantIds` is a unique list of tenantIds from the pieces list. - The purpose is that we need to be able to fetch locations from other - tenants so that we can display all the locations on the full-screen page - */ - receivingTenantIds = DEFAULT_DATA, - /* - ECS mode: - `additionalTenantLocationIdsMap` is a map of tenantId to locationIds for ECS mode. - The format can be: { tenantId: [locationId1, locationId2] } - The purpose is that we need to fetch newly added locations when we select a location - from "Create new holdings for location" modal so that the value is displayed in the selection - */ - additionalTenantLocationIdsMap = {}, - /* - Non-ECS mode: - `additionalLocationIds` is a list of locationIds for the case when we need to fetch additional - locations for the selected location in the form so that the value is displayed in the selection. - */ - additionalLocationIds = [], -}) => { - const { enabled = true, ...queryOptions } = options; +export const useHoldingsAndLocations = ({ instanceId, tenantId, options = {} }) => { + const { enabled = true, ...otherOptions } = options; const ky = useOkapiKy({ tenant: tenantId }); const [namespace] = useNamespace({ key: 'holdings-and-location' }); - const queryKey = [ - namespace, - tenantId, - instanceId, - ...receivingTenantIds, - ...additionalLocationIds, - ...Object.values(additionalTenantLocationIdsMap), - ]; const searchParams = { query: `instanceId==${instanceId}`, limit: LIMIT_MAX, @@ -60,20 +28,32 @@ export const useHoldingsAndLocations = ({ isFetching, isLoading, } = useQuery({ - queryKey, - queryFn: ({ signal }) => { - return receivingTenantIds.length - ? getHoldingLocationsByTenants({ ky, instanceId, receivingTenantIds, additionalTenantLocationIdsMap }) - : getHoldingLocations({ ky, searchParams, signal, additionalLocationIds }); + queryKey: [namespace, tenantId, instanceId], + queryFn: async ({ signal }) => { + const holdings = await ky + .get(HOLDINGS_API, { searchParams, signal }) + .json() + .then(response => response.holdingsRecords); + + const locationIds = holdings?.map(({ permanentLocationId }) => permanentLocationId) || DEFAULT_DATA; + + const locations = await batchRequest( + ({ params }) => ky.get(LOCATIONS_API, { searchParams: params, signal }).json(), + locationIds, + ).then(responses => responses.flatMap(response => response.locations)); + + return { + holdings, + locations, + }; }, enabled: enabled && Boolean(instanceId), - ...queryOptions, + ...otherOptions, }); return ({ holdings: data?.holdings || DEFAULT_DATA, locations: data?.locations || DEFAULT_DATA, - locationIds: data?.locationIds || DEFAULT_DATA, isFetching, isLoading, }); diff --git a/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.test.js b/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.test.js index d7793964..e9c89add 100644 --- a/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.test.js +++ b/src/common/hooks/useHoldingsAndLocations/useHoldingsAndLocations.test.js @@ -7,17 +7,10 @@ import { renderHook, waitFor, } from '@folio/jest-config-stripes/testing-library/react'; -import { HOLDINGS_API } from '@folio/stripes-acq-components'; import { useOkapiKy } from '@folio/stripes/core'; -import { extendKyWithTenant } from '../../utils'; import { useHoldingsAndLocations } from './useHoldingsAndLocations'; -jest.mock('../../utils', () => ({ - ...jest.requireActual('../../utils'), - extendKyWithTenant: jest.fn().mockReturnValue({ extend: jest.fn() }), -})); - const queryClient = new QueryClient(); const wrapper = ({ children }) => ( @@ -52,41 +45,16 @@ const getMock = jest.fn() describe('useHoldingsAndLocations', () => { beforeEach(() => { - useOkapiKy - .mockClear() - .mockReturnValue({ - get: getMock, - extend: jest.fn(() => ({ - get: jest.fn((path) => { - if (path === HOLDINGS_API) { - return { - json: jest.fn().mockResolvedValue({ holdingsRecords }), - }; - } - - return ({ - json: jest.fn().mockResolvedValue({ locations }), - }); - }), - })), - }); - extendKyWithTenant.mockClear().mockReturnValue({ extend: jest.fn() }); + useOkapiKy.mockClear().mockReturnValue({ + get: getMock, + }); }); - it('should fetch holding locations', async () => { + it('should fetch pieces requests', async () => { const { result } = renderHook(() => useHoldingsAndLocations({ instanceId: '1', tenantId: '2' }), { wrapper }); await waitFor(() => expect(result.current.isLoading).toBeFalsy()); expect(result.current.locations).toEqual(locations); }); - - it('should fetch holding locations with different tenants', async () => { - const receivingTenantIds = ['1', '2']; - const { result } = renderHook(() => useHoldingsAndLocations({ instanceId: '1', receivingTenantIds, tenantId: '2' }), { wrapper }); - - await waitFor(() => expect(result.current.isLoading).toBeFalsy()); - - expect(result.current.locations).toHaveLength(2); - }); });