diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9bdfe4b..d8eefcbe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ UIIN-3437. * When moving item within one holding manually, recalculate other item orders based on their position in the list. Fixes UIIN-3539. * Handle audit-marc dependency: hide audit button. Refs UIIN-3576. * Include additional call numbers in Version History for Inventory Item. Refs UIIN-3558. +* Include additional call numbers in Version History for Inventory Holdings. Refs UIIN-3540. ## [13.0.10](https://github.com/folio-org/ui-inventory/tree/v13.0.10) (2025-09-01) [Full Changelog](https://github.com/folio-org/ui-inventory/compare/v13.0.9...v13.0.10) diff --git a/package.json b/package.json index b2aa173f1..117787a0a 100644 --- a/package.json +++ b/package.json @@ -1071,7 +1071,7 @@ "@folio/eslint-config-stripes": "^8.0.0", "@folio/jest-config-stripes": "^3.0.0", "@folio/service-interaction": "^4.0.0", - "@folio/stripes": "^10.0.0", + "@folio/stripes": "^10.1.0", "@folio/stripes-cli": "^4.0.0", "@folio/stripes-components": "^13.0.0", "@folio/stripes-connect": "^10.0.0", @@ -1124,7 +1124,7 @@ }, "peerDependencies": { "@folio/service-interaction": "^4.0.0", - "@folio/stripes": "^10.0.0", + "@folio/stripes": "^10.1.0", "@folio/stripes-erm-components": "^10.0.0", "@folio/stripes-inventory-components": "^2.0.0", "@folio/stripes-marc-components": "^2.0.0", diff --git a/src/Holding/HoldingVersionHistory/HoldingVersionHistory.js b/src/Holding/HoldingVersionHistory/HoldingVersionHistory.js index 9dfaeab74..0fd02f25e 100644 --- a/src/Holding/HoldingVersionHistory/HoldingVersionHistory.js +++ b/src/Holding/HoldingVersionHistory/HoldingVersionHistory.js @@ -30,6 +30,31 @@ export const getFieldFormatter = referenceData => ({ publicDisplay: value => value.toString(), }); +export const getItemFormatter = (fieldLabelsMap, fieldFormatter) => (element, i) => { + if (!element) return null; + + const { name: fieldName, value, collectionName } = element; + const compositeKey = collectionName && fieldName + ? `${collectionName}.${fieldName}` + : null; + + const label = (compositeKey && fieldLabelsMap?.[compositeKey]) + || fieldLabelsMap?.[fieldName] + || fieldLabelsMap?.[collectionName]; + + const formattedValue = (compositeKey && fieldFormatter?.[compositeKey]?.(value)) + || fieldFormatter?.[fieldName]?.(value) + || fieldFormatter?.[collectionName]?.(value) + || value; + + return ( +
  • + {fieldName && {label}: } + {formattedValue} +
  • + ); +}; + const HoldingVersionHistory = ({ onClose, holdingId }) => { const { formatMessage } = useIntl(); const referenceData = useContext(DataContext); @@ -81,9 +106,35 @@ const HoldingVersionHistory = ({ onClose, holdingId }) => { acquisitionMethod: formatMessage({ id: 'ui-inventory.acquisitionMethod' }), receiptStatus: formatMessage({ id: 'ui-inventory.receiptStatus' }), entries: formatMessage({ id: 'ui-inventory.receivingHistory' }), + additionalCallNumbers: formatMessage({ id: 'ui-inventory.additionalCallNumbers' }), + 'additionalCallNumbers.prefix': formatMessage({ id: 'ui-inventory.additionalCallNumberPrefix' }), + 'additionalCallNumbers.suffix': formatMessage({ id: 'ui-inventory.additionalCallNumberSuffix' }), + 'additionalCallNumbers.typeId': formatMessage({ id: 'ui-inventory.additionalCallNumberType' }), + 'additionalCallNumbers.callNumber': formatMessage({ id: 'ui-inventory.additionalCallNumber' }), + 'holdingsStatements.statement': formatMessage({ id: 'ui-inventory.holdingsStatement' }), + 'holdingsStatements.note': formatMessage({ id: 'ui-inventory.holdingsStatementPublicNote' }), + 'holdingsStatements.staffNote': formatMessage({ id: 'ui-inventory.holdingsStatementStaffNote' }), + 'holdingsStatementsForSupplements.statement': formatMessage({ id: 'ui-inventory.holdingsStatementForSupplements' }), + 'holdingsStatementsForSupplements.note': formatMessage({ id: 'ui-inventory.holdingsStatementForSupplementsPublicNote' }), + 'holdingsStatementsForSupplements.staffNote': formatMessage({ id: 'ui-inventory.holdingsStatementForSupplementsStaffNote' }), + 'holdingsStatementsForIndexes.statement': formatMessage({ id: 'ui-inventory.holdingsStatementForIndexes' }), + 'holdingsStatementsForIndexes.note': formatMessage({ id: 'ui-inventory.holdingsStatementForIndexesPublicNote' }), + 'holdingsStatementsForIndexes.staffNote': formatMessage({ id: 'ui-inventory.holdingsStatementForIndexesStaffNote' }), + 'notes.holdingsNoteTypeId': formatMessage({ id: 'ui-inventory.noteType' }), + 'notes.note': formatMessage({ id: 'ui-inventory.note' }), + 'notes.staffOnly': formatMessage({ id: 'ui-inventory.staffOnly' }), + 'electronicAccess.urlRelationship': formatMessage({ id: 'ui-inventory.urlRelationship' }), + 'electronicAccess.uri': formatMessage({ id: 'ui-inventory.uri' }), + 'electronicAccess.linkText': formatMessage({ id: 'ui-inventory.linkText' }), + 'electronicAccess.materialsSpecification': formatMessage({ id: 'ui-inventory.materialsSpecification' }), + 'electronicAccess.urlPublicNote': formatMessage({ id: 'ui-inventory.urlPublicNote' }), + 'entries.publicDisplay': formatMessage({ id: 'ui-inventory.publicDisplay' }), + 'entries.enumeration': formatMessage({ id: 'ui-inventory.enumeration' }), + 'entries.chronology': formatMessage({ id: 'ui-inventory.chronology' }), }; const fieldFormatter = getFieldFormatter(referenceData); + const itemFormatter = getItemFormatter(fieldLabelsMap, fieldFormatter); return ( { isInitialLoading={isLoading} fieldLabelsMap={fieldLabelsMap} fieldFormatter={fieldFormatter} + itemFormatter={itemFormatter} actionsMap={actionsMap} totalVersions={totalVersions} /> diff --git a/src/Holding/HoldingVersionHistory/HoldingVersionHistory.test.js b/src/Holding/HoldingVersionHistory/HoldingVersionHistory.test.js index 63e1a7a89..e643e12d2 100644 --- a/src/Holding/HoldingVersionHistory/HoldingVersionHistory.test.js +++ b/src/Holding/HoldingVersionHistory/HoldingVersionHistory.test.js @@ -12,7 +12,7 @@ import { } from '../../../test/jest/helpers'; import { DataContext } from '../../contexts'; -import HoldingVersionHistory, { getFieldFormatter } from './HoldingVersionHistory'; +import HoldingVersionHistory, { getFieldFormatter, getItemFormatter } from './HoldingVersionHistory'; jest.mock('@folio/stripes/components', () => ({ ...jest.requireActual('@folio/stripes/components'), @@ -115,3 +115,86 @@ describe('field formatter', () => { expect(fieldFormatter.publicDisplay(false)).toBe('false'); }); }); + +describe('getItemFormatter', () => { + const fieldLabelsMap = { + formerIds: 'Former ID', + additionalCallNumbers: 'Additional call numbers', + notes: 'Notes', + 'additionalCallNumbers.prefix': 'Additional call number prefix', + 'additionalCallNumbers.suffix': 'Additional call number suffix', + 'additionalCallNumbers.typeId': 'Additional call number type', + 'additionalCallNumbers.callNumber': 'Additional call number', + 'notes.holdingsNoteTypeId': 'Note type', + 'notes.note': 'Note', + 'notes.staffOnly': 'Staff only', + }; + + const fieldFormatter = getFieldFormatter(mockReferenceData); + const itemFormatter = getItemFormatter(fieldLabelsMap, fieldFormatter); + + it('should return null for null element', () => { + expect(itemFormatter(null, 0)).toBeNull(); + }); + + it('should return null for undefined element', () => { + expect(itemFormatter(undefined, 0)).toBeNull(); + }); + + it('should format field with collectionName using composite key', () => { + const element = { + name: 'staffOnly', + value: false, + collectionName: 'notes', + }; + + const result = itemFormatter(element, 0); + const { container } = renderWithIntl(result, translationsProperties); + + expect(container.querySelector('strong')).toHaveTextContent('Staff only:'); + expect(container.querySelector('li')).toHaveTextContent('Staff only: false'); + }); + + it('should fallback to fieldName label when composite key not found', () => { + const element = { + name: 'formerIds', + value: '1123', + collectionName: 'unknownCollection', + }; + + const result = itemFormatter(element, 0); + const { container } = renderWithIntl(result, translationsProperties); + + expect(container.querySelector('strong')).toHaveTextContent('Former ID:'); + expect(container.querySelector('li')).toHaveTextContent('Former ID: 1123'); + }); + + it('should fallback to collectionName label when fieldName not found', () => { + const element = { + name: 'unknownField', + value: 'test value', + collectionName: 'notes', + }; + + const result = itemFormatter(element, 0); + const { container } = renderWithIntl(result, translationsProperties); + + expect(container.querySelector('strong')).toHaveTextContent('Notes:'); + expect(container.querySelector('li')).toHaveTextContent('Notes: test value'); + }); + + it('should render additionalCallNumbers.prefix with label and value', () => { + const element = { + name: 'prefix', + value: 'ABC', + collectionName: 'additionalCallNumbers', + }; + + const result = itemFormatter(element, 0); + const { container } = renderWithIntl(result, translationsProperties); + + expect(container.querySelector('li')) + .toHaveTextContent('Additional call number prefix: ABC'); + }); +}); +