Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UIBULKED-349 Update Electronic access - URL relationship #409

Merged
merged 13 commits into from
Nov 14, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* [UIBULKED-332](https://issues.folio.org/browse/UIBULKED-332) Bulk edit actions for holdings notes - find and replace or remove.
* [UIBULKED-333](https://issues.folio.org/browse/UIBULKED-333) Bulk edit actions for holdings notes - change note type.
* [UIBULKED-377](https://issues.folio.org/browse/UIBULKED-377) Not all note types are displayed using "Change note type".
* [UIBULKED-349](https://issues.folio.org/browse/UIBULKED-349) Update Electronic access - URL relationship

## [4.0.0](https://github.com/folio-org/ui-bulk-edit/tree/v4.0.0) (2023-10-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ export const ActionsRow = ({ option, actions, onChange }) => {

{/* Render value fields only in case if actions selected AND action is not from FINAL_ACTIONS */}
{action.name && !FINAL_ACTIONS.includes(action.name) && (
<ValuesColumn option={option} action={action} actionIndex={actionIndex} onChange={onChange} />
<ValuesColumn
option={option}
action={action}
allActions={actions}
actionIndex={actionIndex}
onChange={onChange}
/>
)}

{/* Render additional actions */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ import {
BASE_DATE_FORMAT,
CAPABILITIES,
CONTROL_TYPES,
getDuplicateNoteOptions, getHoldingsNotes,
getDuplicateNoteOptions,
getHoldingsNotes,
getItemStatusOptions,
getItemsWithPlaceholder,
getNotesOptions,
} from '../../../../../constants';
import { FIELD_VALUE_KEY, TEMPORARY_LOCATIONS } from './helpers';
import { useLoanTypes, usePatronGroup } from '../../../../../hooks/api';
import { useItemNotes } from '../../../../../hooks/api/useItemNotes';
import { usePreselectedValue } from '../../../../../hooks/usePreselectedValue';
import { useHoldingsNotes } from '../../../../../hooks/api/useHoldingsNotes';
import { useElectronicAccessRelationships } from '../../../../../hooks/api/useElectronicAccess';

export const ValuesColumn = ({ action, actionIndex, onChange, option }) => {
export const ValuesColumn = ({ action, allActions, actionIndex, onChange, option }) => {
const { formatMessage } = useIntl();
const location = useLocation();
const search = new URLSearchParams(location.search);
Expand All @@ -38,6 +41,12 @@ export const ValuesColumn = ({ action, actionIndex, onChange, option }) => {
const { userGroups } = usePatronGroup({ enabled: isUserCapability });
const { loanTypes, isLoanTypesLoading } = useLoanTypes({ enabled: isItemCapability });
const { itemNotes, usItemNotesLoading } = useItemNotes({ enabled: isItemCapability });

const { electronicAccessRelationships, isElectronicAccessLoading } = useElectronicAccessRelationships({ enabled: isHoldingsCapability });
// exclude from second action the first action value
const filteredElectronicAccessRelationships = electronicAccessRelationships.filter(item => actionIndex === 0 || item.value !== allActions[0]?.value);
const accessRelationshipsWithPlaceholder = getItemsWithPlaceholder(filteredElectronicAccessRelationships);

const { holdingsNotes, isHoldingsNotesLoading } = useHoldingsNotes({ enabled: isHoldingsCapability });
const duplicateNoteOptions = getDuplicateNoteOptions(formatMessage).filter(el => el.value !== option);

Expand Down Expand Up @@ -130,16 +139,16 @@ export const ValuesColumn = ({ action, actionIndex, onChange, option }) => {
<>
<LocationSelection
value={actionValue}
onSelect={location => onChange({ actionIndex, value: location.id, fieldName: FIELD_VALUE_KEY })}
onSelect={loc => onChange({ actionIndex, value: loc.id, fieldName: FIELD_VALUE_KEY })}
placeholder={formatMessage({ id: 'ui-bulk-edit.layer.selectLocation' })}
data-test-id={`textField-${actionIndex}`}
aria-label={formatMessage({ id: 'ui-bulk-edit.ariaLabel.location' })}
/>
<LocationLookup
marginBottom0
isTemporaryLocation={TEMPORARY_LOCATIONS.includes(option)}
onLocationSelected={(location) => onChange({
actionIndex, value: location.id, fieldName: FIELD_VALUE_KEY,
onLocationSelected={(loc) => onChange({
actionIndex, value: loc.id, fieldName: FIELD_VALUE_KEY,
})}
data-testid={`locationLookup-${actionIndex}`}
/>
Expand Down Expand Up @@ -204,6 +213,17 @@ export const ValuesColumn = ({ action, actionIndex, onChange, option }) => {
/>
);

const renderElectronicAccessRelationshipSelect = () => controlType === CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT && (
<Select
id="urlRelationship"
value={action.value}
loading={isElectronicAccessLoading}
onChange={e => onChange({ actionIndex, value: e.target.value, fieldName: FIELD_VALUE_KEY })}
dataOptions={accessRelationshipsWithPlaceholder}
aria-label={formatMessage({ id: 'ui-bulk-edit.ariaLabel.urlRelationshipSelect' })}
/>
);

return (
<Col xs={2} sm={2}>
{renderTextField()}
Expand All @@ -215,6 +235,7 @@ export const ValuesColumn = ({ action, actionIndex, onChange, option }) => {
{renderLoanTypeSelect()}
{renderNoteTypeSelect()}
{renderNoteDuplicateTypeSelect()}
{renderElectronicAccessRelationshipSelect()}
</Col>
);
};
Expand All @@ -227,5 +248,10 @@ ValuesColumn.propTypes = {
value: PropTypes.string,
}),
actionIndex: PropTypes.number,
allActions: PropTypes.arrayOf(PropTypes.shape({
controlType: PropTypes.func,
name: PropTypes.string,
value: PropTypes.string,
})),
onChange: PropTypes.func,
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { createMemoryHistory } from 'history';
import { queryClient } from '../../../../../../test/jest/utils/queryClient';
import { ValuesColumn } from './ValuesColumn';
import { useLoanTypes, usePatronGroup } from '../../../../../hooks/api';
import { CONTROL_TYPES } from '../../../../../constants';
import { CAPABILITIES, CONTROL_TYPES } from '../../../../../constants';

jest.mock('../../../../../hooks/api/useLoanTypes');
jest.mock('../../../../../hooks/api/usePatronGroup');
Expand Down Expand Up @@ -64,6 +64,17 @@ describe('ValuesColumn Component', () => {
await waitFor(() => expect(onChange).toHaveBeenCalled());
});

it('should render TextArea when action type is TEXTAREA', async () => {
const { getByTestId } = renderComponent(() => CONTROL_TYPES.TEXTAREA);
const element = getByTestId('input-textarea-0');
vashjs marked this conversation as resolved.
Show resolved Hide resolved

expect(element).toBeInTheDocument();

fireEvent.change(element, { target: { value: 'textarea value' } });

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

/// continue from the above code
it('should render Select with patron groups when action type is PATRON_GROUP_SELECT', async () => {
const { getByTestId } = renderComponent(() => CONTROL_TYPES.PATRON_GROUP_SELECT);
Expand Down Expand Up @@ -109,13 +120,27 @@ describe('ValuesColumn Component', () => {
await waitFor(() => expect(onChange).toHaveBeenCalled());
});

it('should render select with item note types when action type is LOAN_TYPE', async () => {
it('should render select with item note types when action type is NOTE_SELECT', async () => {
const { container } = renderComponent(() => CONTROL_TYPES.NOTE_SELECT);
const element = container.querySelector('#noteType');

expect(element).toBeInTheDocument();

fireEvent.change(element, { target: { value: 'newLoanType' } });
fireEvent.change(element, { target: { value: 'new note select value' } });

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

it('should render select with item note types when action type is NOTE_SELECT + HOLDINS CAPABILITY', async () => {
const spy = jest.spyOn(URLSearchParams.prototype, 'get');
spy.mockReturnValueOnce(CAPABILITIES.HOLDING);

const { container } = renderComponent(() => CONTROL_TYPES.NOTE_SELECT);
const element = container.querySelector('#noteHoldingsType');
vashjs marked this conversation as resolved.
Show resolved Hide resolved

expect(element).toBeInTheDocument();

fireEvent.change(element, { target: { value: 'new note holding value' } });

await waitFor(() => expect(onChange).toHaveBeenCalled());
});
Expand All @@ -130,4 +155,15 @@ describe('ValuesColumn Component', () => {

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

it('should render select with url relationship types when action type is FIND', async () => {
const { container } = renderComponent(() => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT);
const element = container.querySelector('#urlRelationship');
vashjs marked this conversation as resolved.
Show resolved Hide resolved

expect(element).toBeInTheDocument();

fireEvent.change(element, { target: { value: 'RESOURCE' } });

await waitFor(() => expect(onChange).toHaveBeenCalled());
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
CAPABILITIES,
emailActionsFind,
emailActionsReplace,
noteAdditionalActions,
commonAdditionalActions,
patronActions,
expirationActions,
replaceClearActions,
Expand All @@ -20,6 +20,7 @@ import {
noteActions,
noteActionsWithMark,
noteActionsWithDuplicate,
urlRelationshipActions,
} from '../../../../../constants';

export const ACTION_VALUE_KEY = 'name';
Expand Down Expand Up @@ -291,6 +292,20 @@ export const getDefaultActions = (option, options, formatMessage) => {
],
};

case OPTIONS.URL_RELATIONSHIP:
return {
type: '',
actions: [
null,
{
actionsList: urlRelationshipActions(formatMessage),
controlType: () => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT,
[ACTION_VALUE_KEY]: noteDefaultActions[0].value,
[FIELD_VALUE_KEY]: '',
},
],
};

default:
return {
type: null,
Expand Down Expand Up @@ -362,9 +377,17 @@ export const getExtraActions = (option, action, formattedMessage) => {
case `${OPTIONS.CHECK_OUT_NOTE}-${ACTIONS.FIND}`:
case `${OPTIONS.HOLDINGS_NOTE}-${ACTIONS.FIND}`:
return [{
actionsList: noteAdditionalActions(formattedMessage),
actionsList: commonAdditionalActions(formattedMessage),
controlType: () => CONTROL_TYPES.TEXTAREA,
[ACTION_VALUE_KEY]: noteAdditionalActions(formattedMessage)[0].value,
[ACTION_VALUE_KEY]: commonAdditionalActions(formattedMessage)[0].value,
[FIELD_VALUE_KEY]: '',
}];

case `${OPTIONS.URL_RELATIONSHIP}-${ACTIONS.FIND}`:
return [{
actionsList: commonAdditionalActions(formattedMessage),
controlType: () => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT,
[ACTION_VALUE_KEY]: commonAdditionalActions(formattedMessage)[0].value,
[FIELD_VALUE_KEY]: '',
}];

Expand Down
Loading
Loading