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

UISACQCOMP-194 ECS - Support central ordering in the acq modules #784

Merged
merged 21 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
361e9be
UISACQCOMP-194 ECS - Support central ordering in the acq modules
usavkov-epam Jun 17, 2024
eed5951
update part of components and hooks to support central ordering
usavkov-epam Jun 21, 2024
069d3b2
update filters to support tenant id prop
usavkov-epam Jun 24, 2024
b3fbca6
update hooks and filters to support tenant id option
usavkov-epam Jun 25, 2024
3b743ed
Merge branch 'master' into UISACQCOMP-194
usavkov-epam Jun 25, 2024
80c7f08
Updates tests according to changes
usavkov-epam Jun 25, 2024
dd28fd0
add unit test
usavkov-epam Jun 25, 2024
02f252c
fix issue with closing the lookup
usavkov-epam Jun 25, 2024
2a31dff
update changelog
usavkov-epam Jun 25, 2024
dca6486
remove redundant code
usavkov-epam Jun 25, 2024
1b18900
update react query hook
usavkov-epam Jun 25, 2024
a7651da
adapt more hooks and components to work with central ordering
usavkov-epam Jun 27, 2024
4879f07
Merge branch 'UISACQCOMP-194' of https://github.com/folio-org/stripes…
usavkov-epam Jun 27, 2024
6fc5985
fix test
usavkov-epam Jun 27, 2024
54b21bf
tests
usavkov-epam Jul 1, 2024
dddc2ac
remove unused imports
usavkov-epam Jul 1, 2024
7c0d324
one more hook adapted to central ordering enabled
usavkov-epam Jul 1, 2024
0c00795
Merge branch 'UISACQCOMP-194' of https://github.com/folio-org/stripes…
usavkov-epam Jul 1, 2024
ff17c46
fix test
usavkov-epam Jul 1, 2024
6e1b5d5
resolve code smells
usavkov-epam Jul 1, 2024
b20f061
Merge branch 'UISACQCOMP-194' of https://github.com/folio-org/stripes…
usavkov-epam Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Correctly manage state setting in the `toggle` function of the `useToggle` hook. Refs UISACQCOMP-189.
* ECS - Support affiliations select for the inventory field (`<ConsortiumFieldInventory>`). Refs UISACQCOMP-190.
* Add Print routing list functionality. Refs UISACQCOMP-191.
* ECS - Support central ordering in the acq modules. Refs UISACQCOMP-194.

## [5.1.1](https://github.com/folio-org/stripes-acq-components/tree/v5.1.1) (2024-04-22)
[Full Changelog](https://github.com/folio-org/stripes-acq-components/compare/v5.1.0...v5.1.1)
Expand Down
39 changes: 19 additions & 20 deletions lib/AcqTagsFilter/AcqTagsFilter.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React, { useMemo } from 'react';
import { useMemo } from 'react';
import PropTypes from 'prop-types';
import { get } from 'lodash';

import { MultiSelectionFilter } from '@folio/stripes/smart-components';
import { stripesConnect } from '@folio/stripes/core';

import { FilterAccordion } from '../FilterAccordion';
import {
configTags,
tagsResource,
} from '../manifests';
useTags,
useTagsConfigs,
} from '../hooks';

const getTagsOptions = resources => {
return get(resources, 'tagsFilter.records', []).map(tag => ({
const getTagsOptions = (tags) => {
return tags.map(tag => ({
label: tag.label,
value: tag.label,
}));
Expand All @@ -26,12 +24,18 @@ const AcqTagsFilter = ({
labelId,
name,
onChange,
resources,
tenantId,
}) => {
const tags = useMemo(() => getTagsOptions(resources), [resources]);
const { configs, isFetched } = useTagsConfigs({ tenantId });

const tagSettings = get(resources, ['configTags', 'records'], []);
const tagsEnabled = !tagSettings.length || tagSettings[0].value === 'true';
const tagsEnabled = isFetched && (!configs.length || configs[0].value === 'true');

const { tags } = useTags({
tenantId,
enabled: tagsEnabled,
});

const tagsOptions = useMemo(() => getTagsOptions(tags), [tags]);

if (!tagsEnabled) return false;

Expand All @@ -47,7 +51,7 @@ const AcqTagsFilter = ({
>
<MultiSelectionFilter
ariaLabelledBy={`accordion-toggle-button-${id}`}
dataOptions={tags}
dataOptions={tagsOptions}
disabled={disabled}
id="acq-tags-filter"
name={name}
Expand All @@ -58,11 +62,6 @@ const AcqTagsFilter = ({
);
};

AcqTagsFilter.manifest = Object.freeze({
tagsFilter: tagsResource,
configTags,
});

AcqTagsFilter.propTypes = {
activeFilters: PropTypes.arrayOf(PropTypes.string),
closedByDefault: PropTypes.bool,
Expand All @@ -71,7 +70,7 @@ AcqTagsFilter.propTypes = {
labelId: PropTypes.string,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
resources: PropTypes.object.isRequired,
tenantId: PropTypes.string,
};

AcqTagsFilter.defaultProps = {
Expand All @@ -80,4 +79,4 @@ AcqTagsFilter.defaultProps = {
labelId: 'stripes-acq-components.filter.tags',
};

export default stripesConnect(AcqTagsFilter);
export default AcqTagsFilter;
26 changes: 22 additions & 4 deletions lib/AcqTagsFilter/AcqTagsFilter.test.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import {
render,
screen,
} from '@testing-library/react';
import user from '@testing-library/user-event';

import {
useTags,
useTagsConfigs,
} from '../hooks';
import AcqTagsFilter from './AcqTagsFilter';

jest.mock('../hooks', () => ({
...jest.requireActual('../hooks'),
useTags: jest.fn(),
useTagsConfigs: jest.fn(),
}));

const TAGS_FILTER_LABEL = 'stripes-acq-components.filter.tags';
const TAGS = [{
id: 'tag1',
label: 'tag 1',
}];

const renderAcqTagsFilter = (props = {}) => (render(
const renderAcqTagsFilter = (props = {}) => render(
<AcqTagsFilter
id="tags-filter"
name="tags-filter"
{...props}
/>,
));
);

describe('AcqTagsFilter', () => {
const onChange = jest.fn();

beforeEach(() => {
onChange.mockClear();
useTags
.mockClear()
.mockReturnValue({ tags: TAGS });
useTagsConfigs
.mockClear()
.mockReturnValue({ configs: [], isFetched: true });
});

it('should display Tags filter', () => {
Expand Down
19 changes: 6 additions & 13 deletions lib/AcqUnitFilter/AcqUnitFilterContainer.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types';

import { stripesConnect } from '@folio/stripes/core';

import { acqUnitsManifest } from '../manifests';
import { useAcquisitionUnits } from '../hooks';
import AcqUnitFilter from './AcqUnitFilter';

const AcqUnitFilterContainer = ({ resources, ...rest }) => {
const acqUnitsRecords = resources.acqUnits?.records;
const AcqUnitFilterContainer = ({ tenantId, ...rest }) => {
const { acquisitionsUnits } = useAcquisitionUnits({ tenantId });

return (
<AcqUnitFilter
labelId="stripes-acq-components.filter.acqUnit"
{...rest}
acqUnits={acqUnitsRecords}
acqUnits={acquisitionsUnits}
/>
);
};

AcqUnitFilterContainer.manifest = Object.freeze({
acqUnits: acqUnitsManifest,
});

AcqUnitFilterContainer.propTypes = {
resources: PropTypes.object.isRequired,
tenantId: PropTypes.string,
};

export default stripesConnect(AcqUnitFilterContainer);
export default AcqUnitFilterContainer;
91 changes: 30 additions & 61 deletions lib/AcqUnits/AcqUnitsField/AcqUnitsFieldContainer.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import React, { useEffect, useState } from 'react';
import compact from 'lodash/compact';
import difference from 'lodash/difference';
import uniq from 'lodash/uniq';
import PropTypes from 'prop-types';
import { get, uniq, compact, difference } from 'lodash';

import {
stripesConnect,
stripesShape,
} from '@folio/stripes/core';

import { LIMIT_MAX } from '../../constants';
import { baseManifest } from '../../manifests';
import { usePrevious } from '../../utils';
import { useStripes } from '@folio/stripes/core';

import { useAcquisitionUnits } from '../../hooks';
import { useAcqUnitsMemberships } from '../hooks';
import AcqUnitsField from './AcqUnitsField';

export const buildAcqUnitsQuery = (memberUnits, preselectedUnits, isEdit) => {
Expand All @@ -32,76 +28,49 @@ export const buildAcqUnitsQuery = (memberUnits, preselectedUnits, isEdit) => {
};

const AcqUnitsFieldContainer = ({
name, mutator, stripes, preselectedUnits, perm, isEdit, isFinal, id,
name,
preselectedUnits,
perm,
isEdit,
isFinal,
id,
tenantId,
}) => {
const userId = get(stripes, 'user.user.id');
const prevUserId = usePrevious(userId);
const [units, setUnits] = useState([]);

useEffect(() => {
if (userId !== prevUserId) {
mutator.acqUnitMemberships.reset();
mutator.acqUnitsEdit.reset();
const stripes = useStripes();
const userId = stripes?.user?.user?.id;

mutator.acqUnitMemberships.GET({
params: {
limit: LIMIT_MAX,
query: `userId==${userId}`,
},
}).then(memberships => {
const query = buildAcqUnitsQuery(
memberships.map(({ acquisitionsUnitId }) => acquisitionsUnitId),
preselectedUnits,
isEdit,
);
const { acquisitionsUnitMemberships } = useAcqUnitsMemberships(userId, { tenantId });

if (query.length) {
mutator.acqUnitsEdit.GET({
params: {
limit: LIMIT_MAX,
query,
},
}).then(setUnits);
}
});
}
const { acquisitionsUnits } = useAcquisitionUnits({
tenantId,
searchParams: {
query: buildAcqUnitsQuery(
acquisitionsUnitMemberships.map(({ acquisitionsUnitId }) => acquisitionsUnitId),
preselectedUnits,
isEdit,
),
},
});

return (
<AcqUnitsField
id={id}
name={name}
units={units}
units={acquisitionsUnits}
disabled={perm ? !stripes.hasPerm(perm) : false}
isFinal={isFinal}
/>
);
};

AcqUnitsFieldContainer.manifest = Object.freeze({
acqUnitMemberships: {
...baseManifest,
path: 'acquisitions-units/memberships',
records: 'acquisitionsUnitMemberships',
accumulate: true,
},
acqUnitsEdit: {
...baseManifest,
path: 'acquisitions-units/units',
records: 'acquisitionsUnits',
accumulate: true,
},
});

AcqUnitsFieldContainer.propTypes = {
stripes: stripesShape.isRequired,
mutator: PropTypes.object.isRequired,
name: PropTypes.string,
preselectedUnits: PropTypes.arrayOf(PropTypes.string),
perm: PropTypes.string,
preselectedUnits: PropTypes.arrayOf(PropTypes.string),
id: PropTypes.string,
isEdit: PropTypes.bool,
isFinal: PropTypes.bool,
id: PropTypes.string,
tenantId: PropTypes.string,
};

AcqUnitsFieldContainer.defaultProps = {
Expand All @@ -112,4 +81,4 @@ AcqUnitsFieldContainer.defaultProps = {
isFinal: false,
};

export default stripesConnect(AcqUnitsFieldContainer);
export default AcqUnitsFieldContainer;
51 changes: 30 additions & 21 deletions lib/AcqUnits/AcqUnitsField/AcqUnitsFieldContainer.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';

import { useAcquisitionUnits } from '../../hooks';
import { useAcqUnitsMemberships } from '../hooks';
import AcqUnitsField from './AcqUnitsField';
import AcqUnitsFieldContainer from './AcqUnitsFieldContainer';

jest.mock('../../hooks', () => ({
...jest.requireActual('../../hooks'),
useAcquisitionUnits: jest.fn(),
}));
jest.mock('../hooks', () => ({
...jest.requireActual('../hooks'),
useAcqUnitsMemberships: jest.fn(),
}));
jest.mock('./AcqUnitsField', () => {
return jest.fn(() => 'AcqUnitsField');
});

const MEMBERSHIP = [{
'id': '3b552ce3-da49-49be-a1f8-a7a6617f16cc',
'userId': 'e5e96ab2-694f-5222-b616-34befa6125bb',
Expand All @@ -20,40 +33,36 @@ const UNITS = [{
'protectDelete': true,
}];

jest.mock('./AcqUnitsField', () => {
return jest.fn(() => 'AcqUnitsField');
});
const defaultProps = {
id: 'units',
name: 'units',
};

const renderComponent = (props = {}) => (render(
<MemoryRouter>
<AcqUnitsFieldContainer
id="units"
name="units"
{...defaultProps}
{...props}
/>
</MemoryRouter>,
));

describe('AcqUnitsFieldContainer', () => {
const mutator = {
acqUnitMemberships: {
GET: jest.fn().mockResolvedValue(MEMBERSHIP),
reset: jest.fn(),
},
acqUnitsEdit: {
GET: jest.fn().mockResolvedValue(UNITS),
reset: jest.fn(),
},
};

beforeEach(() => {
AcqUnitsField.mockClear();
useAcquisitionUnits
.mockClear()
.mockReturnValue({ acquisitionsUnits: UNITS });
useAcqUnitsMemberships
.mockClear()
.mockReturnValue({ acquisitionsUnitMemberships: MEMBERSHIP });
});

it('should load and pass units', async () => {
it('should load and pass units', () => {
const preselectedUnits = ['1ed3cc28-c0da-423e-b9d4-5b9917b2fa69'];

renderComponent({ mutator, preselectedUnits });
await waitFor(() => expect(AcqUnitsField.mock.calls[1][0].units).toEqual(UNITS));
renderComponent({ preselectedUnits });

expect(AcqUnitsField.mock.calls[0][0].units).toEqual(UNITS);
});
});
Loading
Loading