Skip to content

Commit

Permalink
UIBULKED-349 Update Electronic access - URL relationship (#409)
Browse files Browse the repository at this point in the history
  • Loading branch information
vashjs authored Nov 14, 2023
1 parent f2bef8f commit 16cd64e
Show file tree
Hide file tree
Showing 11 changed files with 683 additions and 377 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* [UIBULKED-371](https://issues.folio.org/browse/UIBULKED-371) Bulk edit - Grouped form controls missing accessible name.
* [UIBULKED-353](https://issues.folio.org/browse/UIBULKED-353) Update Electronic access - URI.
* [UIBULKED-356](https://issues.folio.org/browse/UIBULKED-356) Separate holdings notes by 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 @@ -54,8 +54,8 @@ describe('ValuesColumn Component', () => {
});

it('should render TextField when action type is INPUT', async () => {
const { getByTestId } = renderComponent(() => CONTROL_TYPES.INPUT);
const element = getByTestId('input-email-0');
const { getByRole } = renderComponent(() => CONTROL_TYPES.INPUT);
const element = getByRole('textbox');

expect(element).toBeInTheDocument();

Expand All @@ -64,10 +64,21 @@ describe('ValuesColumn Component', () => {
await waitFor(() => expect(onChange).toHaveBeenCalled());
});

it('should render TextArea when action type is TEXTAREA', async () => {
const { getByRole } = renderComponent(() => CONTROL_TYPES.TEXTAREA);
const element = getByRole('textbox');

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);
const element = getByTestId('select-patronGroup-0');
const { getByRole } = renderComponent(() => CONTROL_TYPES.PATRON_GROUP_SELECT);
const element = getByRole('combobox');

expect(element).toBeInTheDocument();

Expand All @@ -77,8 +88,8 @@ describe('ValuesColumn Component', () => {
});

it('should render Datepicker when action type is DATE', async () => {
const { getByTestId } = renderComponent(() => CONTROL_TYPES.DATE);
const element = getByTestId('dataPicker-experation-date-0');
const { getByRole } = renderComponent(() => CONTROL_TYPES.DATE);
const element = getByRole('textbox');

expect(element).toBeInTheDocument();

Expand All @@ -88,8 +99,8 @@ describe('ValuesColumn Component', () => {
});

it('should render Select with status options when action type is STATUS_SELECT', async () => {
const { getByTestId } = renderComponent(() => CONTROL_TYPES.STATUS_SELECT);
const element = getByTestId('select-statuses-0');
const { getByRole } = renderComponent(() => CONTROL_TYPES.STATUS_SELECT);
const element = getByRole('combobox');

expect(element).toBeInTheDocument();

Expand All @@ -109,25 +120,50 @@ describe('ValuesColumn Component', () => {
await waitFor(() => expect(onChange).toHaveBeenCalled());
});

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

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 { getByRole } = renderComponent(() => CONTROL_TYPES.NOTE_SELECT);
const element = getByRole('combobox');

expect(element).toBeInTheDocument();

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

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

it('should render select with item note types when action type is DUPLICATE', async () => {
const { container } = renderComponent(() => CONTROL_TYPES.NOTE_DUPLICATE_SELECT);
const element = container.querySelector('#noteTypeDuplicate');
const { getByRole } = renderComponent(() => CONTROL_TYPES.NOTE_DUPLICATE_SELECT);
const element = getByRole('combobox');

expect(element).toBeInTheDocument();

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

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

it('should render select with url relationship types when action type is FIND', async () => {
const { getByRole } = renderComponent(() => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT);
const element = getByRole('combobox');

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 Down Expand Up @@ -293,7 +293,21 @@ export const getDefaultActions = (option, options, formatMessage) => {
],
};

case OPTIONS.URI:
case OPTIONS.ELECTRONIC_ACCESS_URL_RELATIONSHIP:
return {
type: '',
actions: [
null,
{
actionsList: electronicAccessActions,
controlType: () => CONTROL_TYPES.ELECTRONIC_ACCESS_RELATIONSHIP_SELECT,
[ACTION_VALUE_KEY]: electronicAccessActions[0].value,
[FIELD_VALUE_KEY]: '',
},
],
};

case OPTIONS.ELECTRONIC_ACCESS_URI:
return {
type: '',
actions: [
Expand Down Expand Up @@ -374,14 +388,22 @@ export const getExtraActions = (option, action, formattedMessage) => {
switch (`${option}-${action}`) {
case `${OPTIONS.ITEM_NOTE}-${ACTIONS.FIND}`:
case `${OPTIONS.ADMINISTRATIVE_NOTE}-${ACTIONS.FIND}`:
case `${OPTIONS.URI}-${ACTIONS.FIND}`:
case `${OPTIONS.ELECTRONIC_ACCESS_URI}-${ACTIONS.FIND}`:
case `${OPTIONS.CHECK_IN_NOTE}-${ACTIONS.FIND}`:
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.ELECTRONIC_ACCESS_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

0 comments on commit 16cd64e

Please sign in to comment.