-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UISACQCOMP-223: ECS - Add reusable custom hooks to fix invalid refere…
…nce issues related to holding names and locations (#824) * UISACQCOMP-223: ECS - Add reusable custom hooks to fix invalid reference issues related to holding names and locations * test: fix failing tests * test: add test coverage * fix hook key * refactor: rename custom hooks
- Loading branch information
1 parent
9285e73
commit 330bcac
Showing
13 changed files
with
480 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useReceivingTenantIdsAndLocations'; |
47 changes: 47 additions & 0 deletions
47
lib/hooks/useReceivingTenantIdsAndLocations/useReceivingTenantIdsAndLocations.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import uniq from 'lodash/uniq'; | ||
import { useMemo } from 'react'; | ||
|
||
import { useCurrentUserTenants } from '../consortia'; | ||
|
||
/* | ||
The purpose of this hook is to generate the list of unique tenantIds and locationIds | ||
for the receiving tenant and locations when we need to fetch locations from other tenants via `useTenantHoldingsAndLocations` | ||
*/ | ||
export const useReceivingTenantIdsAndLocations = ({ | ||
currentReceivingTenantId, | ||
currentLocationId: locationId, | ||
receivingTenantIds = [], | ||
}) => { | ||
const currentUserTenants = useCurrentUserTenants(); | ||
|
||
const receivingTenants = useMemo(() => { | ||
if (receivingTenantIds.length) { | ||
const currentUserTenantIds = currentUserTenants?.map(({ id: tenantId }) => tenantId); | ||
|
||
// should get unique tenantIds from poLine locations and filter out tenantIds where the current user has assigned | ||
return uniq([ | ||
...receivingTenantIds, | ||
currentReceivingTenantId, | ||
].filter((tenantId) => currentUserTenantIds?.includes(tenantId)) | ||
.filter(Boolean)); | ||
} | ||
|
||
return []; | ||
}, [receivingTenantIds, currentUserTenants, currentReceivingTenantId]); | ||
|
||
const additionalLocations = useMemo(() => { | ||
const locationIds = locationId ? [locationId] : []; | ||
const tenantLocationIdsMap = currentReceivingTenantId ? { [currentReceivingTenantId]: locationIds } : {}; | ||
|
||
return { | ||
additionalLocationIds: locationIds, | ||
additionalTenantLocationIdsMap: tenantLocationIdsMap, | ||
}; | ||
}, [locationId, currentReceivingTenantId]); | ||
|
||
return { | ||
receivingTenantIds: receivingTenants, | ||
tenantId: currentReceivingTenantId, | ||
...additionalLocations, | ||
}; | ||
}; |
33 changes: 33 additions & 0 deletions
33
lib/hooks/useReceivingTenantIdsAndLocations/useReceivingTenantIdsAndLocations.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
|
||
import { useReceivingTenantIdsAndLocations } from './useReceivingTenantIdsAndLocations'; | ||
|
||
jest.mock('../consortia', () => ({ | ||
useCurrentUserTenants: jest.fn(() => [{ id: 'central' }, { id: 'college' }]), | ||
})); | ||
|
||
describe('useReceivingTenantIdsAndLocations', () => { | ||
it('should return receivingTenantIds', () => { | ||
const tenants = ['central', 'college']; | ||
const { result } = renderHook(() => useReceivingTenantIdsAndLocations({ | ||
receivingTenantIds: tenants, | ||
currentReceivingTenantId: 'central', | ||
})); | ||
|
||
expect(result.current.receivingTenantIds).toEqual(tenants); | ||
}); | ||
|
||
it('should return tenantId', () => { | ||
const currentReceivingTenantId = 'central'; | ||
|
||
const { result } = renderHook(() => useReceivingTenantIdsAndLocations({ currentReceivingTenantId })); | ||
|
||
expect(result.current.tenantId).toBe(currentReceivingTenantId); | ||
}); | ||
|
||
it('should return additionalLocationIds', () => { | ||
const { result } = renderHook(() => useReceivingTenantIdsAndLocations({})); | ||
|
||
expect(result.current.additionalLocationIds).toEqual([]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { useTenantHoldingsAndLocations } from './useTenantHoldingsAndLocations'; |
84 changes: 84 additions & 0 deletions
84
lib/hooks/useTenantHoldingsAndLocations/useTenantHoldingsAndLocations.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { useQuery } from 'react-query'; | ||
|
||
import { | ||
useNamespace, | ||
useOkapiKy, | ||
} from '@folio/stripes/core'; | ||
|
||
import { LIMIT_MAX } from '../../constants'; | ||
import { | ||
getHoldingsAndLocations, | ||
getHoldingsAndLocationsByTenants, | ||
} from '../../utils'; | ||
|
||
const DEFAULT_DATA = []; | ||
|
||
/* | ||
The purpose of this hook is to fetch holdings and locations for a given instanceId | ||
and tenants when we need to fetch locations from other tenants when Central ordering is enabled. | ||
*/ | ||
export const useTenantHoldingsAndLocations = ({ | ||
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; | ||
|
||
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, | ||
}; | ||
|
||
const { | ||
data, | ||
isFetching, | ||
isLoading, | ||
} = useQuery({ | ||
queryKey, | ||
queryFn: ({ signal }) => { | ||
return receivingTenantIds.length | ||
? getHoldingsAndLocationsByTenants({ ky, instanceId, receivingTenantIds, additionalTenantLocationIdsMap }) | ||
: getHoldingsAndLocations({ ky, searchParams, signal, additionalLocationIds }); | ||
}, | ||
enabled: enabled && Boolean(instanceId), | ||
...queryOptions, | ||
}); | ||
|
||
return ({ | ||
holdings: data?.holdings || DEFAULT_DATA, | ||
locations: data?.locations || DEFAULT_DATA, | ||
locationIds: data?.locationIds || DEFAULT_DATA, | ||
isFetching, | ||
isLoading, | ||
}); | ||
}; |
91 changes: 91 additions & 0 deletions
91
lib/hooks/useTenantHoldingsAndLocations/useTenantHoldingsAndLocations.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { | ||
QueryClient, | ||
QueryClientProvider, | ||
} from 'react-query'; | ||
|
||
import { | ||
renderHook, | ||
} from '@testing-library/react-hooks'; | ||
import { useOkapiKy } from '@folio/stripes/core'; | ||
|
||
import { HOLDINGS_API } from '../../constants'; | ||
import { extendKyWithTenant } from '../../utils'; | ||
import { useTenantHoldingsAndLocations } from './useTenantHoldingsAndLocations'; | ||
|
||
jest.mock('../../utils', () => ({ | ||
...jest.requireActual('../../utils'), | ||
extendKyWithTenant: jest.fn().mockReturnValue({ extend: jest.fn() }), | ||
})); | ||
|
||
const queryClient = new QueryClient(); | ||
const wrapper = ({ children }) => ( | ||
<QueryClientProvider client={queryClient}> | ||
{children} | ||
</QueryClientProvider> | ||
); | ||
|
||
const holdingsRecords = [ | ||
{ | ||
'id': 'd7e99892-6d7d-46eb-8a4c-3aa471785819', | ||
'instanceId': '8804aeeb-db18-4c42-b0e9-28d63c7855e6', | ||
'permanentLocationId': '9d1b77e8-f02e-4b7f-b296-3f2042ddac54', | ||
}, | ||
{ | ||
'id': '5636949f-8f97-4b25-a0fc-90fdb050ffb0', | ||
'instanceId': '8804aeeb-db18-4c42-b0e9-28d63c7855e6', | ||
'permanentLocationId': '9d1b77e8-f02e-4b7f-b296-3f2042ddac54', | ||
}, | ||
]; | ||
|
||
const locations = [ | ||
{ | ||
'id': '9d1b77e8-f02e-4b7f-b296-3f2042ddac54', | ||
'name': 'DCB', | ||
'code': '000', | ||
}, | ||
]; | ||
|
||
const getMock = jest.fn() | ||
.mockReturnValueOnce({ json: () => Promise.resolve({ holdingsRecords }) }) | ||
.mockReturnValue({ json: () => Promise.resolve({ locations }) }); | ||
|
||
describe('useTenantHoldingsAndLocations', () => { | ||
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() }); | ||
}); | ||
|
||
it('should fetch holding locations', async () => { | ||
const { result, waitFor } = renderHook(() => useTenantHoldingsAndLocations({ 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, waitFor } = renderHook(() => useTenantHoldingsAndLocations({ instanceId: '1', receivingTenantIds, tenantId: '2' }), { wrapper }); | ||
|
||
await waitFor(() => expect(result.current.isLoading).toBeFalsy()); | ||
|
||
expect(result.current.locations).toHaveLength(2); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { OKAPI_TENANT_HEADER } from '../constants'; | ||
|
||
export const extendKyWithTenant = (ky, tenantId) => { | ||
return ky.extend({ | ||
hooks: { | ||
beforeRequest: [ | ||
request => { | ||
request.headers.set(OKAPI_TENANT_HEADER, tenantId); | ||
}, | ||
], | ||
}, | ||
}); | ||
}; |
Oops, something went wrong.