-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UIIN-3174: Holdings: Display all versions in View history second pane (…
- Loading branch information
1 parent
2dba643
commit f19ea5c
Showing
11 changed files
with
319 additions
and
5 deletions.
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
111 changes: 111 additions & 0 deletions
111
src/Holding/HoldingVersionHistory/HoldingVersionHistory.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,111 @@ | ||
import { | ||
useContext, | ||
useState, | ||
} from 'react'; | ||
import { useIntl } from 'react-intl'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { AuditLogPane } from '@folio/stripes/components'; | ||
|
||
import { | ||
useHoldingAuditDataQuery, | ||
useInventoryVersionHistory, | ||
} from '../../hooks'; | ||
import { DataContext } from '../../contexts'; | ||
|
||
export const getFieldFormatter = referenceData => ({ | ||
discoverySuppress: value => value.toString(), | ||
holdingsTypeId: value => referenceData.holdingsTypes?.find(type => type.id === value)?.name, | ||
statisticalCodeIds: value => { | ||
const statisticalCode = referenceData.statisticalCodes?.find(code => code.id === value); | ||
|
||
return `${statisticalCode.statisticalCodeType.name}: ${statisticalCode.code} - ${statisticalCode.name}`; | ||
}, | ||
callNumberTypeId: value => referenceData.callNumberTypes?.find(type => type.id === value)?.name, | ||
permanentLocationId: value => referenceData.locationsById[value]?.name, | ||
temporaryLocationId: value => referenceData.locationsById[value]?.name, | ||
effectiveLocationId: value => referenceData.locationsById[value]?.name, | ||
illPolicyId: value => referenceData.illPolicies.find(policy => policy.id === value)?.name, | ||
staffOnly: value => value.toString(), | ||
holdingsNoteTypeId: value => referenceData.holdingsNoteTypes?.find(noteType => noteType.id === value)?.name, | ||
relationshipId: value => referenceData.electronicAccessRelationships?.find(noteType => noteType.id === value)?.name, | ||
publicDisplay: value => value.toString(), | ||
}); | ||
|
||
const HoldingVersionHistory = ({ onClose, holdingId }) => { | ||
const { formatMessage } = useIntl(); | ||
const referenceData = useContext(DataContext); | ||
|
||
const [lastVersionEventTs, setLastVersionEventTs] = useState(null); | ||
|
||
const { | ||
data, | ||
totalRecords, | ||
isLoading, | ||
} = useHoldingAuditDataQuery(holdingId, lastVersionEventTs); | ||
|
||
const { | ||
actionsMap, | ||
versions, | ||
isLoadMoreVisible, | ||
} = useInventoryVersionHistory({ data, totalRecords }); | ||
|
||
const fieldLabelsMap = { | ||
discoverySuppress: formatMessage({ id: 'ui-inventory.discoverySuppressed' }), | ||
hrid: formatMessage({ id: 'ui-inventory.holdingsHrid' }), | ||
sourceId: formatMessage({ id: 'ui-inventory.holdingsSourceLabel' }), | ||
formerIds: formatMessage({ id: 'ui-inventory.formerHoldingsId' }), | ||
holdingsTypeId: formatMessage({ id: 'ui-inventory.holdingsType' }), | ||
statisticalCodeIds: formatMessage({ id: 'ui-inventory.statisticalCodes' }), | ||
administrativeNotes: formatMessage({ id: 'ui-inventory.administrativeNotes' }), | ||
permanentLocationId: formatMessage({ id: 'ui-inventory.permanentLocation' }), | ||
temporaryLocationId: formatMessage({ id: 'ui-inventory.temporaryLocation' }), | ||
effectiveLocationId: formatMessage({ id: 'ui-inventory.effectiveLocationHoldings' }), | ||
shelvingOrder: formatMessage({ id: 'ui-inventory.shelvingOrder' }), | ||
shelvingTitle: formatMessage({ id: 'ui-inventory.shelvingTitle' }), | ||
copyNumber: formatMessage({ id: 'ui-inventory.copyNumber' }), | ||
callNumberTypeId: formatMessage({ id: 'ui-inventory.callNumberType' }), | ||
callNumberPrefix: formatMessage({ id: 'ui-inventory.callNumberPrefix' }), | ||
callNumber: formatMessage({ id: 'ui-inventory.callNumber' }), | ||
callNumberSuffix: formatMessage({ id: 'ui-inventory.callNumberSuffix' }), | ||
numberOfItems: formatMessage({ id: 'ui-inventory.numberOfItems' }), | ||
holdingsStatements: formatMessage({ id: 'ui-inventory.holdingsStatements' }), | ||
holdingsStatementsForIndexes: formatMessage({ id: 'ui-inventory.holdingsStatementForIndexes' }), | ||
holdingsStatementsForSupplements: formatMessage({ id: 'ui-inventory.holdingsStatementForSupplements' }), | ||
digitizationPolicy: formatMessage({ id: 'ui-inventory.digitizationPolicy' }), | ||
illPolicyId: formatMessage({ id: 'ui-inventory.illPolicy' }), | ||
retentionPolicy: formatMessage({ id: 'ui-inventory.retentionPolicy' }), | ||
notes: formatMessage({ id: 'ui-inventory.notes' }), | ||
electronicAccess: formatMessage({ id: 'ui-inventory.electronicAccess' }), | ||
acquisitionFormat: formatMessage({ id: 'ui-inventory.acquisitionFormat' }), | ||
acquisitionMethod: formatMessage({ id: 'ui-inventory.acquisitionMethod' }), | ||
receiptStatus: formatMessage({ id: 'ui-inventory.receiptStatus' }), | ||
entries: formatMessage({ id: 'ui-inventory.receivingHistory' }), | ||
}; | ||
|
||
const fieldFormatter = getFieldFormatter(referenceData); | ||
|
||
const handleLoadMore = lastEventTs => { | ||
setLastVersionEventTs(lastEventTs); | ||
}; | ||
|
||
return ( | ||
<AuditLogPane | ||
versions={versions} | ||
onClose={onClose} | ||
isLoadMoreVisible={isLoadMoreVisible} | ||
handleLoadMore={handleLoadMore} | ||
isLoading={isLoading} | ||
fieldLabelsMap={fieldLabelsMap} | ||
fieldFormatter={fieldFormatter} | ||
actionsMap={actionsMap} | ||
/> | ||
); | ||
}; | ||
|
||
HoldingVersionHistory.propTypes = { | ||
holdingId: PropTypes.string.isRequired, | ||
onClose: PropTypes.func.isRequired, | ||
}; | ||
|
||
export default HoldingVersionHistory; |
117 changes: 117 additions & 0 deletions
117
src/Holding/HoldingVersionHistory/HoldingVersionHistory.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,117 @@ | ||
import { | ||
QueryClient, | ||
QueryClientProvider, | ||
} from 'react-query'; | ||
import { screen } from '@folio/jest-config-stripes/testing-library/react'; | ||
import { runAxeTest } from '@folio/stripes-testing'; | ||
|
||
import { act } from 'react'; | ||
import { | ||
renderWithIntl, | ||
translationsProperties, | ||
} from '../../../test/jest/helpers'; | ||
|
||
import { DataContext } from '../../contexts'; | ||
import HoldingVersionHistory, { getFieldFormatter } from './HoldingVersionHistory'; | ||
|
||
jest.mock('@folio/stripes/components', () => ({ | ||
...jest.requireActual('@folio/stripes/components'), | ||
AuditLogPane: () => <div>Version history</div>, | ||
})); | ||
|
||
jest.mock('../../hooks', () => ({ | ||
...jest.requireActual('../../hooks'), | ||
useHoldingAuditDataQuery: jest.fn().mockReturnValue({ data: [{}], isLoading: false }), | ||
})); | ||
|
||
const queryClient = new QueryClient(); | ||
|
||
const onCloseMock = jest.fn(); | ||
const holdingId = 'holdingId'; | ||
const mockReferenceData = { | ||
holdingsTypes: [{ id: 'holding-type-1', name: 'Holding type 1' }], | ||
statisticalCodes: [{ id: 'stat-1', statisticalCodeType: { name: 'Category' }, code: '001', name: 'Stat Code' }], | ||
callNumberTypes: [{ id: '123', name: 'Test Call Number Type' }], | ||
locationsById: { 'location-1': { name: 'Main Library' } }, | ||
illPolicies: [{ id: 'ill-policy-1', name: 'Ill policy 1' }], | ||
holdingsNoteTypes: [{ id: 'h-note-type-1', name: 'H note type 1' }], | ||
electronicAccessRelationships: [{ id: 'rel-1', name: 'Online Access' }], | ||
}; | ||
|
||
const renderHoldingVersionHistory = () => { | ||
const component = ( | ||
<QueryClientProvider client={queryClient}> | ||
<DataContext.Provider value={mockReferenceData}> | ||
<HoldingVersionHistory | ||
holdingId={holdingId} | ||
onClose={onCloseMock} | ||
/> | ||
</DataContext.Provider> | ||
</QueryClientProvider> | ||
); | ||
|
||
return renderWithIntl(component, translationsProperties); | ||
}; | ||
|
||
describe('HoldingVersionHistory', () => { | ||
it('should be rendered with no axe errors', async () => { | ||
const { container } = await act(async () => renderHoldingVersionHistory()); | ||
|
||
await runAxeTest({ rootNode: container }); | ||
}); | ||
|
||
it('should render View history pane', () => { | ||
renderHoldingVersionHistory(); | ||
|
||
expect(screen.getByText('Version history')).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe('field formatter', () => { | ||
const fieldFormatter = getFieldFormatter(mockReferenceData); | ||
|
||
it('should format discoverySuppress field correctly', () => { | ||
expect(fieldFormatter.discoverySuppress(true)).toBe('true'); | ||
expect(fieldFormatter.discoverySuppress(false)).toBe('false'); | ||
}); | ||
|
||
it('should format holdingsTypeId field correctly', () => { | ||
expect(fieldFormatter.holdingsTypeId('holding-type-1')).toBe('Holding type 1'); | ||
}); | ||
|
||
it('should format statistical codes field correctly', () => { | ||
expect(fieldFormatter.statisticalCodeIds('stat-1')).toBe('Category: 001 - Stat Code'); | ||
}); | ||
|
||
it('should format typeId callNumberTypeId correctly', () => { | ||
expect(fieldFormatter.callNumberTypeId('123')).toBe('Test Call Number Type'); | ||
}); | ||
|
||
it('should format location IDs field correctly', () => { | ||
expect(fieldFormatter.permanentLocationId('location-1')).toBe('Main Library'); | ||
expect(fieldFormatter.effectiveLocationId('location-1')).toBe('Main Library'); | ||
expect(fieldFormatter.temporaryLocationId('location-1')).toBe('Main Library'); | ||
}); | ||
|
||
it('should format illPolicyId field correctly', () => { | ||
expect(fieldFormatter.illPolicyId('ill-policy-1')).toBe('Ill policy 1'); | ||
}); | ||
|
||
it('should format staffOnly field correctly', () => { | ||
expect(fieldFormatter.staffOnly(true)).toBe('true'); | ||
expect(fieldFormatter.staffOnly(false)).toBe('false'); | ||
}); | ||
|
||
it('should format holdingsNoteTypeId field correctly', () => { | ||
expect(fieldFormatter.holdingsNoteTypeId('h-note-type-1')).toBe('H note type 1'); | ||
}); | ||
|
||
it('should format electronic access relationships field correctly', () => { | ||
expect(fieldFormatter.relationshipId('rel-1')).toBe('Online Access'); | ||
}); | ||
|
||
it('should format publicDisplay field correctly', () => { | ||
expect(fieldFormatter.publicDisplay(true)).toBe('true'); | ||
expect(fieldFormatter.publicDisplay(false)).toBe('false'); | ||
}); | ||
}); |
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 { default as HoldingVersionHistory } from './HoldingVersionHistory'; |
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 { default } from './useHoldingAuditDataQuery'; |
30 changes: 30 additions & 0 deletions
30
src/hooks/useHoldingAuditDataQuery/useHoldingAuditDataQuery.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,30 @@ | ||
import { useQuery } from 'react-query'; | ||
|
||
import { | ||
useNamespace, | ||
useOkapiKy, | ||
} from '@folio/stripes/core'; | ||
|
||
const useHoldingAuditDataQuery = (holdingId, eventTs) => { | ||
const ky = useOkapiKy(); | ||
const [namespace] = useNamespace({ key: 'holding-audit-data' }); | ||
|
||
// eventTs param is used to load more data | ||
const { isLoading, data = {} } = useQuery({ | ||
queryKey: [namespace, holdingId, eventTs], | ||
queryFn: () => ky.get(`audit-data/inventory/holdings/${holdingId}`, { | ||
searchParams: { | ||
...(eventTs && { eventTs }) | ||
} | ||
}).json(), | ||
enabled: Boolean(holdingId), | ||
}); | ||
|
||
return { | ||
data: data?.inventoryAuditItems || [], | ||
totalRecords: data?.totalRecords, | ||
isLoading, | ||
}; | ||
}; | ||
|
||
export default useHoldingAuditDataQuery; |
46 changes: 46 additions & 0 deletions
46
src/hooks/useHoldingAuditDataQuery/useHoldingAuditDataQuery.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,46 @@ | ||
import React, { act } from 'react'; | ||
import { | ||
QueryClient, | ||
QueryClientProvider, | ||
} from 'react-query'; | ||
|
||
import { renderHook } from '@folio/jest-config-stripes/testing-library/react'; | ||
import { useOkapiKy } from '@folio/stripes/core'; | ||
|
||
import '../../../test/jest/__mock__'; | ||
|
||
import useHoldingAuditDataQuery from './useHoldingAuditDataQuery'; | ||
|
||
jest.mock('@folio/stripes/core', () => ({ | ||
...jest.requireActual('@folio/stripes/core'), | ||
useOkapiKy: jest.fn(), | ||
})); | ||
|
||
const queryClient = new QueryClient(); | ||
const wrapper = ({ children }) => ( | ||
<QueryClientProvider client={queryClient}> | ||
{children} | ||
</QueryClientProvider> | ||
); | ||
|
||
describe('useHoldingAuditDataQuery', () => { | ||
beforeEach(() => { | ||
useOkapiKy.mockClear().mockReturnValue({ | ||
get: () => ({ | ||
json: () => Promise.resolve({ inventoryAuditItems: [{ action: 'UPDATE' }] }), | ||
}), | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('should fetch holdings', async () => { | ||
const { result } = renderHook(() => useHoldingAuditDataQuery('holdingId'), { wrapper }); | ||
|
||
await act(() => !result.current.isLoading); | ||
|
||
expect(result.current.data).toEqual([{ action: 'UPDATE' }]); | ||
}); | ||
}); |