Skip to content

Commit

Permalink
UIBULKED-562 Include statistical code option on Instances bulk edit f…
Browse files Browse the repository at this point in the history
…orms (#663)
  • Loading branch information
vashjs authored Dec 16, 2024
1 parent 1fbeece commit 2345a2d
Show file tree
Hide file tree
Showing 16 changed files with 429 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [UIBULKED-560](https://folio-org.atlassian.net/browse/UIBULKED-560) Update actions menu.
* [UIBULKED-585](https://folio-org.atlassian.net/browse/UUIBULKED-585) Adding missing translation and filters.
* [UIBULKED-561](https://folio-org.atlassian.net/browse/UUIBULKED-561) Add administrative data accordion to MARC bulk edit form.
* [UIBULKED-562](https://folio-org.atlassian.net/browse/UIBULKED-562) Include statistical code option on Instances bulk edit forms.

## [4.2.2](https://github.com/folio-org/ui-bulk-edit/tree/v4.2.2) (2024-11-15)

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
"consortia.publications-results.item.get",
"consortium-search.institutions.collection.get",
"consortium-search.campuses.collection.get",
"consortium-search.libraries.collection.get"
"consortium-search.libraries.collection.get",
"inventory-storage.statistical-codes.collection.get",
"inventory-storage.statistical-code-types.collection.get"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { InstanceNotesControl } from './controls/InstanceNotesControl';
import { ElectronicAccessRelationshipControl } from './controls/ElectronicAccessRelationshipControl';
import { DuplicateNoteControl } from './controls/DuplicateNotesControl';
import { StatusControl } from './controls/StatusControl';
import { InstanceStatisticalCodesControl } from './controls/InstanceStatisticalCodesControl';


export const ValuesColumn = ({ action, allActions, actionIndex, onChange, option }) => {
Expand Down Expand Up @@ -150,6 +151,13 @@ export const ValuesColumn = ({ action, allActions, actionIndex, onChange, option
/>
);

const renderStatisticalCodesSelect = () => controlType === CONTROL_TYPES.STATISTICAL_CODES_SELECT && (
<InstanceStatisticalCodesControl
actionName={action.name}
{...sharedProps}
/>
);

return (
<>
{renderTextField()}
Expand All @@ -162,6 +170,7 @@ export const ValuesColumn = ({ action, allActions, actionIndex, onChange, option
{renderNoteTypeSelect()}
{renderNoteDuplicateTypeSelect()}
{renderElectronicAccessRelationshipSelect()}
{renderStatisticalCodesSelect()}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,33 @@ import { createMemoryHistory } from 'history';
import { runAxeTest } from '@folio/stripes-testing';
import { queryClient } from '../../../../../../test/jest/utils/queryClient';
import { ValuesColumn } from './ValuesColumn';
import { useElectronicAccessRelationships, useLoanTypes, usePatronGroup } from '../../../../../hooks/api';
import {
useElectronicAccessRelationships,
useLoanTypes,
usePatronGroup,
useStatisticalCodes
} from '../../../../../hooks/api';
import { CAPABILITIES, CONTROL_TYPES } from '../../../../../constants';


jest.mock('../../../../../hooks/api/useLoanTypes');
jest.mock('../../../../../hooks/api/usePatronGroup');
jest.mock('../../../../../hooks/api/useElectronicAccess');
jest.mock('../../../../../hooks/api/useStatisticalCodes');

const onChange = jest.fn();

const history = createMemoryHistory();

const mockAction = {
type: '',
name: 'testName',
value: 'testValue',
};
const renderComponent = (actionType, override = {}) => {
const action = {
type: '',
name: 'testName',
value: 'testValue',
controlType: actionType,
...override,
};

const renderComponent = (actionType) => {
const action = { ...mockAction, controlType: actionType };
return render(
<Router history={history}>
<QueryClientProvider client={queryClient}>
Expand All @@ -54,11 +62,11 @@ describe('ValuesColumn Component', () => {
isElectronicAccessLoading: false,
electronicAccessRelationships: [],
});
});

afterEach(() => {
usePatronGroup.mockReset();
useLoanTypes.mockReset();
useStatisticalCodes.mockReturnValue({
statisticalCodes: [],
isStatisticalCodesLoading: false,
});
});

it('should render TextField when action type is INPUT', async () => {
Expand Down Expand Up @@ -191,6 +199,22 @@ describe('ValuesColumn Component', () => {
await waitFor(() => expect(onChange).toHaveBeenCalled());
});

it('should render select with statistical codes when action type is ADD, or REMOVE_SOME', async () => {
const { getByRole } = renderComponent(
() => CONTROL_TYPES.STATISTICAL_CODES_SELECT,
{
value: [{ label: 'test', value: 'test' }],
}
);
const element = getByRole('combobox');

expect(element).toBeInTheDocument();

fireEvent.change(element, [{ label: 'test', value: 'test' }]);

await waitFor(() => expect(onChange).toHaveBeenCalled());
});

it('should render with no axe errors', async () => {
renderComponent(() => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';

import { Loading, MultiSelection } from '@folio/stripes/components';

import { FIELD_VALUE_KEY, getLabelByValue, sortWithoutPlaceholder } from '../helpers';
import { useStatisticalCodes } from '../../../../../../hooks/api/useStatisticalCodes';
import { customMultiSelectionFilter } from '../../../../../../utils/helpers';


export const InstanceStatisticalCodesControl = ({ actionName, actionValue, actionIndex, onChange }) => {
const { formatMessage } = useIntl();

const { statisticalCodes, isStatisticalCodesLoading } = useStatisticalCodes();
const sortedStatisticalCodes = sortWithoutPlaceholder(statisticalCodes);
const title = getLabelByValue(sortedStatisticalCodes, actionValue);

const handleChange = value => {
onChange({
actionIndex,
value,
fieldName: FIELD_VALUE_KEY,
});
};

if (isStatisticalCodesLoading) return <Loading size="large" />;

return (
<div title={title}>
<MultiSelection
key={actionName}
id="statisticalCodes"
value={actionValue}
onChange={handleChange}
placeholder={formatMessage({ id: 'ui-bulk-edit.layer.statisticalCode' })}
aria-label={formatMessage({ id: 'ui-bulk-edit.ariaLabel.statisticalCode' })}
dataOptions={statisticalCodes}
dirty={!!actionValue}
filter={customMultiSelectionFilter}
/>
</div>
);
};

InstanceStatisticalCodesControl.propTypes = {
actionValue: PropTypes.arrayOf(PropTypes.object),
actionName: PropTypes.string,
actionIndex: PropTypes.number,
onChange: PropTypes.func,
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
noteActionsWithMarc,
noteActionsWithDuplicate,
electronicAccess,
statisticalCodeActions,
} from '../../../../../constants';
import { getActionParameters } from '../../../../../constants/actionParameters';

Expand Down Expand Up @@ -89,6 +90,7 @@ export const getDefaultActions = ({
const expirationDefaultActions = expirationActions();
const holdingsLocationDefaultActions = permanentHoldingsLocation();
const suppressDefaultActions = suppressFromDiscActions();
const statisticalCodeDefaultActions = statisticalCodeActions();
const statusDefaultActions = statusActions();
const loanDefaultActions = permanentLoanTypeActions();
const noteDefaultActions = noteActions();
Expand Down Expand Up @@ -196,6 +198,19 @@ export const getDefaultActions = ({
},
],
};
case OPTIONS.STATISTICAL_CODE:
return {
type: '',
actions: [
null,
{
actionsList: statisticalCodeDefaultActions,
controlType: () => CONTROL_TYPES.STATISTICAL_CODES_SELECT,
[ACTION_VALUE_KEY]: statisticalCodeDefaultActions[0].value,
[FIELD_VALUE_KEY]: '',
},
],
};
case OPTIONS.STAFF_SUPPRESS:
return {
type: '',
Expand Down Expand Up @@ -425,6 +440,8 @@ export const getLabelByValue = (items, targetValue) => {
};

export const sortWithoutPlaceholder = (array) => {
if (!array.length) return [];

const [placeholder, ...rest] = array;

return [placeholder, ...rest.sort((a, b) => a.label.localeCompare(b.label))];
Expand All @@ -433,7 +450,13 @@ export const sortWithoutPlaceholder = (array) => {
export const getMappedContentUpdates = (fields, options) => fields.map(({
parameters, tenants, option, actionsDetails: { actions }
}) => {
const [initial, updated] = actions.map(action => action?.value ?? null);
const [initial, updated] = actions.map(action => {
if (Array.isArray(action?.value)) {
return action.value.map(item => item?.value).join(',');
}

return action?.value || null;
});
const actionTenants = actions.map(action => action?.tenants);
const sourceOption = options.find(o => o.value === option);
const optionType = sourceOption?.type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,50 @@ describe('ContentUpdatesForm helpers', () => {
);
});

it('returns the correct object for the ELECTRONIC_ACCESS_MATERIALS_SPECIFIED option', () => {
expect(JSON.stringify(getDefaultActions({
option: OPTIONS.STATISTICAL_CODE,
options: [],
formatMessage,
capability: CAPABILITIES.INSTANCE
})))
.toEqual(
JSON.stringify({
type: '',
actions: [
null,
{
actionsList: [
{
value: '',
label: <FormattedMessage id="ui-bulk-edit.actions.placeholder" />,
disabled: true,
},
{
value: ACTIONS.ADD_TO_EXISTING,
label: <FormattedMessage id="ui-bulk-edit.layer.options.add" />,
disabled: false,
},
{
value: ACTIONS.REMOVE_SOME,
label: <FormattedMessage id="ui-bulk-edit.layer.options.items.removeNote" />,
disabled: false,
},
{
value: ACTIONS.REMOVE_ALL,
label: <FormattedMessage id="ui-bulk-edit.layer.options.items.removeAll" />,
disabled: false,
},
],
controlType: () => CONTROL_TYPES.STATISTICAL_CODES_SELECT,
[ACTION_VALUE_KEY]: '',
[FIELD_VALUE_KEY]: '',
},
],
}),
);
});

it('returns the correct object for the default case', () => {
expect(getDefaultActions({
option: 'unknown',
Expand Down
1 change: 1 addition & 0 deletions src/constants/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const CONTROL_TYPES = {
NOTE_SELECT: 'NOTE_SELECT',
NOTE_DUPLICATE_SELECT: 'NOTE_DUPLICATE_SELECT',
ELECTRONIC_ACCESS_RELATIONSHIP_SELECT: 'ELECTRONIC_ACCESS_RELATIONSHIP_SELECT',
STATISTICAL_CODES_SELECT: 'STATISTICAL_CODES_SELECT',
};

export const TRANSLATION_SUFFIX = {
Expand Down
15 changes: 15 additions & 0 deletions src/constants/inAppActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const ACTIONS = {
MARK_AS_STAFF_ONLY: 'MARK_AS_STAFF_ONLY',
REMOVE_MARK_AS_STAFF_ONLY: 'REMOVE_MARK_AS_STAFF_ONLY',
REMOVE_ALL: 'REMOVE_ALL',
REMOVE_SOME: 'REMOVE_SOME',
CHANGE_TYPE: 'CHANGE_TYPE',
DUPLICATE: 'DUPLICATE',

Expand Down Expand Up @@ -119,6 +120,12 @@ export const getRemoveTheseAction = () => ({
disabled: false,
});

export const getRemoveSomeAction = () => ({
value: ACTIONS.REMOVE_SOME,
label: <FormattedMessage id="ui-bulk-edit.layer.options.items.removeNote" />,
disabled: false,
});

export const getDuplicateToNoteAction = () => ({
value: ACTIONS.DUPLICATE,
label: <FormattedMessage id="ui-bulk-edit.layer.options.items.duplicateTo" />,
Expand All @@ -142,6 +149,14 @@ export const suppressFromDiscActions = () => [
getSetToTrueAction(),
getSetToFalseAction(),
];

export const statisticalCodeActions = () => [
getPlaceholder(),
getAddAction(),
getRemoveSomeAction(),
getRemoveAllAction(),
];

export const noteActions = () => [
getPlaceholder(),
getAddToExistingAction(),
Expand Down
12 changes: 12 additions & 0 deletions src/constants/selectOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const OPTIONS = {
TEMPORARY_LOCATION: 'TEMPORARY_LOCATION',
PERMANENT_LOCATION: 'PERMANENT_LOCATION',
SUPPRESS_FROM_DISCOVERY: 'SUPPRESS_FROM_DISCOVERY',
STATISTICAL_CODE: 'STATISTICAL_CODE',
STAFF_SUPPRESS: 'STAFF_SUPPRESS',
STATUS: 'STATUS',
EXPIRATION_DATE: 'EXPIRATION_DATE',
Expand Down Expand Up @@ -287,6 +288,12 @@ export const getInstanceOptions = (formatMessage, instanceNotes) => [
disabled: false,
categoryName: formatMessage({ id: 'ui-bulk-edit.category.administrativeData' }),
},
{
value: OPTIONS.STATISTICAL_CODE,
label: formatMessage({ id: 'ui-bulk-edit.layer.options.instances.statisticalCode' }),
disabled: false,
categoryName: formatMessage({ id: 'ui-bulk-edit.category.administrativeData' }),
},
...instanceNotes
];

Expand All @@ -306,6 +313,11 @@ export const getAdministrativeDataOptions = (formatMessage) => [
label: formatMessage({ id: 'ui-bulk-edit.layer.options.instances.suppress' }),
disabled: false,
},
{
value: OPTIONS.STATISTICAL_CODE,
label: formatMessage({ id: 'ui-bulk-edit.layer.options.instances.statisticalCode' }),
disabled: false,
},
];

export const getHoldingsNotes = (formatMessage, holdingsNotes) => [
Expand Down
1 change: 1 addition & 0 deletions src/hooks/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export * from './useHoldingsNotesEcs';
export * from './useLocationEcs';
export * from './useLoanTypesEcs';
export * from './useElectronicAccessEcs';
export * from './useStatisticalCodes';
Loading

0 comments on commit 2345a2d

Please sign in to comment.