Skip to content

Commit

Permalink
UISACQCOMP-168: extend <Donors /> component props (#730)
Browse files Browse the repository at this point in the history
* UISACQCOMP-168: extend `<Donors />` component props

* fix: failing test case

* tests: add test coverages

* fix: add donors lookup specific column props

* tests: add test coverage

* fix: select all and sorting issue

* update loading for donors list

* improve useFetchDonors hook
  • Loading branch information
alisher-epam authored Nov 16, 2023
1 parent f28d3b2 commit fcf089d
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Add `inputType` prop to `<SingleSearchForm>`. Refs UISACQCOMP-165.
* View the list of donors. Refs UISACQCOMP-166.
* Added `indexRef` and `inputRef` props to `<SingleSearchForm>`. Refs UISACQCOMP-167.
* Extend Donors component functionality. Refs UISACQCOMP-168.

## [5.0.0](https://github.com/folio-org/stripes-acq-components/tree/v5.0.0) (2023-10-12)
[Full Changelog](https://github.com/folio-org/stripes-acq-components/compare/v4.0.2...v5.0.0)
Expand Down
28 changes: 19 additions & 9 deletions lib/Donors/Donors.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { noop } from 'lodash';
import PropTypes from 'prop-types';
import { FieldArray } from 'react-final-form-arrays';
import { useState } from 'react';
import { useEffect, useState } from 'react';

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

import { defaultColumnMapping } from './constants';
import { DonorsContainer } from './DonorsContainer';
import { useFetchDonors } from './hooks';

export function Donors({ name, donorOrganizationIds, ...rest }) {
export function Donors({ name, donorOrganizationIds, onChange, ...rest }) {
const [donorIds, setDonorIds] = useState(donorOrganizationIds);
const { donors, isLoading } = useFetchDonors(donorIds);
const { donors, isLoading } = useFetchDonors(donorIds, { keepPreviousData: true });

if (isLoading) {
return <Loading />;
}
useEffect(() => {
setDonorIds(donorOrganizationIds);
}, [donorOrganizationIds]);

const onSetDonorIds = (values = []) => {
setDonorIds(values);
onChange(values);
};

return (
<Row>
Expand All @@ -27,8 +32,9 @@ export function Donors({ name, donorOrganizationIds, ...rest }) {
name={name}
id={name}
component={DonorsContainer}
setDonorIds={setDonorIds}
setDonorIds={onSetDonorIds}
donors={donors}
loading={isLoading}
{...rest}
/>
</Col>
Expand All @@ -41,13 +47,17 @@ Donors.propTypes = {
columnWidths: PropTypes.object,
donorOrganizationIds: PropTypes.arrayOf(PropTypes.string),
name: PropTypes.string,
onChange: PropTypes.func,
onRemove: PropTypes.func,
searchLabel: PropTypes.node,
showTriggerButton: PropTypes.bool,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

Donors.defaultProps = {
columnMapping: defaultColumnMapping,
donorOrganizationIds: [],
name: 'donorOrganizationIds',
columnMapping: defaultColumnMapping,
onChange: noop,
onRemove: noop,
};
29 changes: 19 additions & 10 deletions lib/Donors/Donors.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import user from '@testing-library/user-event';

import stripesFinalForm from '@folio/stripes/final-form';

import { Donors } from './Donors';
import { useFetchDonors } from './hooks';

jest.mock('@folio/stripes/components', () => ({
...jest.requireActual('@folio/stripes/components'),
Loading: jest.fn(() => 'Loading'),
jest.mock('./DonorsLookup', () => ({
DonorsLookup: jest.fn(({ onAddDonors }) => (
<button
type="button"
onClick={() => onAddDonors([{ id: 'donorId' }])}
>
Add donor
</button>
)),
}));

jest.mock('./hooks', () => ({
Expand All @@ -21,6 +28,7 @@ jest.mock('./hooks', () => ({
const defaultProps = {
name: 'donors',
donorOrganizationIds: [],
onChange: jest.fn(),
};

const renderForm = (props = {}) => (
Expand Down Expand Up @@ -55,14 +63,15 @@ describe('Donors', () => {
expect(screen.getByText('stripes-components.tableEmpty')).toBeDefined();
});

it('should render Loading component', () => {
useFetchDonors.mockClear().mockReturnValue({
donors: [],
isLoading: true,
});
it('should call onChange when donorOrganizationIds changed', () => {
const onChange = jest.fn();

renderComponent();
renderComponent({ onChange });

const addDonorButton = screen.getByText('Add donor');

user.click(addDonorButton);

expect(screen.getByText('Loading')).toBeDefined();
expect(onChange).toHaveBeenCalled();
});
});
12 changes: 7 additions & 5 deletions lib/Donors/DonorsContainer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { map, sortBy } from 'lodash';
import { map, noop, sortBy } from 'lodash';
import PropTypes from 'prop-types';
import { useMemo } from 'react';
import { useIntl } from 'react-intl';
Expand All @@ -17,6 +17,7 @@ export function DonorsContainer({
fields,
formatter,
id,
onRemove,
setDonorIds,
searchLabel,
showTriggerButton,
Expand Down Expand Up @@ -45,11 +46,11 @@ export function DonorsContainer({
};
}), [donorsMap, fields.value]);

const contentData = useMemo(() => sortBy(listOfDonors, [({ lastName }) => lastName?.toLowerCase()]), [listOfDonors]);
const contentData = useMemo(() => sortBy(listOfDonors, [({ name }) => name?.toLowerCase()]), [listOfDonors]);

const resultsFormatter = useMemo(() => {
return formatter || getDonorsFormatter({ intl, fields, canViewOrganizations });
}, [canViewOrganizations, fields, formatter, intl]);
return formatter || getDonorsFormatter({ intl, fields, canViewOrganizations, onRemove });
}, [canViewOrganizations, fields, formatter, intl, onRemove]);

const onAddDonors = (values = []) => {
const addedDonorIds = new Set(fields.value);
Expand Down Expand Up @@ -79,7 +80,6 @@ export function DonorsContainer({
onAddDonors={onAddDonors}
name={id}
searchLabel={searchLabel}
visibleColumns={visibleColumns}
/>
)
}
Expand All @@ -94,13 +94,15 @@ DonorsContainer.propTypes = {
fields: PropTypes.object,
formatter: PropTypes.object,
id: PropTypes.string,
onRemove: PropTypes.func,
searchLabel: PropTypes.node,
setDonorIds: PropTypes.func.isRequired,
showTriggerButton: PropTypes.bool,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

DonorsContainer.defaultProps = {
onRemove: noop,
showTriggerButton: true,
visibleColumns: defaultContainerVisibleColumns,
};
4 changes: 2 additions & 2 deletions lib/Donors/DonorsContainer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('DonorsContainer', () => {
expect(screen.getByText(mockData[0].name)).toBeDefined();
});

it('should call `setDonorIds` when `onAddDonors` is called', async () => {
it('should call `setDonorIds` when `onAddDonors` is called', () => {
renderComponent({
donors: [mockVendor],
fields: {
Expand All @@ -114,7 +114,7 @@ describe('DonorsContainer', () => {
const addDonorsButton = screen.getByText('Add donor');

expect(addDonorsButton).toBeDefined();
await user.click(addDonorsButton);
user.click(addDonorsButton);
expect(setDonorIds).toHaveBeenCalled();
});

Expand Down
2 changes: 2 additions & 0 deletions lib/Donors/DonorsLookup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
pluginVisibleColumns,
resultsPaneTitle,
searchableIndexes,
sortableColumns,
visibleFilters,
} from './constants';

Expand Down Expand Up @@ -41,6 +42,7 @@ export const DonorsLookup = ({
searchableIndexes={searchableIndexes}
visibleFilters={visibleFilters}
isMultiSelect
sortableColumns={sortableColumns}
>
<span data-test-add-donor>
<FormattedMessage id="stripes-acq-components.donors.noFindOrganizationPlugin" />
Expand Down
2 changes: 2 additions & 0 deletions lib/Donors/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const defaultVisibleColumns = [
'code',
];

export const sortableColumns = ['name', 'code'];

export const defaultContainerVisibleColumns = [
...defaultVisibleColumns,
'unassignDonor',
Expand Down
7 changes: 5 additions & 2 deletions lib/Donors/hooks/useFetchDonors/useFetchDonors.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { VENDORS_API } from '../../../constants';
import { batchRequest } from '../../../utils';
import { DEFAULT_DATA } from './constants';

export const useFetchDonors = (donorOrganizationIds = DEFAULT_DATA) => {
export const useFetchDonors = (donorOrganizationIds = DEFAULT_DATA, options = {}) => {
const ky = useOkapiKy();
const namespace = useNamespace({ key: 'fetch-donors-list' });

Expand All @@ -24,7 +24,10 @@ export const useFetchDonors = (donorOrganizationIds = DEFAULT_DATA) => {
donorOrganizationIds,
);
},
{ enabled: Boolean(donorOrganizationIds.length) },
{
enabled: Boolean(donorOrganizationIds.length),
...options,
},
);

return ({
Expand Down
1 change: 1 addition & 0 deletions lib/Donors/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { Donors } from './Donors';
export { DonorsList } from './DonorsList';
export { DonorsListContainer } from './DonorsListContainer';
export { DonorsLookup } from './DonorsLookup';
export { useFetchDonors } from './hooks/useFetchDonors';
8 changes: 7 additions & 1 deletion lib/Donors/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ export const getDonorsListFormatter = ({ canViewOrganizations }) => ({
code: donor => donor.code,
});

export const getDonorsFormatter = ({ canViewOrganizations, fields, intl }) => ({
export const getDonorsFormatter = ({
canViewOrganizations,
fields,
intl,
onRemove,
}) => ({
...getDonorsListFormatter({ canViewOrganizations }),
unassignDonor: donor => (
<Button
Expand All @@ -27,6 +32,7 @@ export const getDonorsFormatter = ({ canViewOrganizations, fields, intl }) => ({
onClick={(e) => {
e.preventDefault();
fields.remove(donor._index);
onRemove(fields.value[donor._index]);
}}
>
<Icon icon="times-circle" />
Expand Down
8 changes: 8 additions & 0 deletions lib/Donors/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import {
getDonorsFormatter,
} from './utils';

const mockOnRemove = jest.fn();
const defaultProps = {
canViewOrganizations: true,
fields: {
remove: jest.fn(),
value: ['1'],
},
intl: {
formatMessage: jest.fn((id) => id),
},
onRemove: mockOnRemove,
};

describe('getDonorsListFormatter', () => {
Expand All @@ -31,5 +34,10 @@ describe('getDonorsFormatter', () => {
expect(result).toEqual(expect.objectContaining({
unassignDonor: expect.any(Function),
}));

result.unassignDonor({ _index: 0 }).props.onClick({ preventDefault: jest.fn() });

expect(defaultProps.fields.remove).toHaveBeenCalled();
expect(mockOnRemove).toHaveBeenCalled();
});
});

0 comments on commit fcf089d

Please sign in to comment.