From 44033b8cc20f4af12086efae7ec7f0f28f08d3f6 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Tue, 31 Oct 2023 13:46:22 +0500 Subject: [PATCH 01/16] UISACQCOMP-166: view list of donors --- lib/DonorsList/DonorsContainer.js | 65 +++++++ lib/DonorsList/DonorsList.js | 165 ++++++++++++++++++ lib/DonorsList/hooks/index.js | 1 + lib/DonorsList/hooks/useFetchDonors/index.js | 1 + .../hooks/useFetchDonors/useFetchDonors.js | 36 ++++ lib/DonorsList/index.js | 1 + lib/index.js | 1 + translations/stripes-acq-components/en.json | 5 +- 8 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 lib/DonorsList/DonorsContainer.js create mode 100644 lib/DonorsList/DonorsList.js create mode 100644 lib/DonorsList/hooks/index.js create mode 100644 lib/DonorsList/hooks/useFetchDonors/index.js create mode 100644 lib/DonorsList/hooks/useFetchDonors/useFetchDonors.js create mode 100644 lib/DonorsList/index.js diff --git a/lib/DonorsList/DonorsContainer.js b/lib/DonorsList/DonorsContainer.js new file mode 100644 index 00000000..37765fe4 --- /dev/null +++ b/lib/DonorsList/DonorsContainer.js @@ -0,0 +1,65 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { FieldArray } from 'react-final-form-arrays'; + +import { + Col, + Loading, + Row, +} from '@folio/stripes/components'; + +import DonorsList from './DonorsList'; +import { useFetchDonors } from './hooks'; + +function DonorsContainer({ name, donorOrganizationIds }) { + const [donors, setDonors] = useState([]); + const { fetchDonorsMutation, isLoading } = useFetchDonors(); + + const handleFetchDonors = useCallback(ids => { + fetchDonorsMutation({ donorOrganizationIds: ids }) + .then((data) => { + setDonors(data); + }); + }, [fetchDonorsMutation]); + + useEffect(() => { + if (donorOrganizationIds.length) { + handleFetchDonors(donorOrganizationIds); + } + }, [donorOrganizationIds, handleFetchDonors]); + + const donorsMap = donors.reduce((acc, contact) => { + acc[contact.id] = contact; + + return acc; + }, {}); + + if (isLoading) { + return ; + } + + return ( + + + + + + ); +} + +DonorsContainer.propTypes = { + name: PropTypes.string.isRequired, + donorOrganizationIds: PropTypes.arrayOf(PropTypes.string), +}; + +DonorsContainer.defaultProps = { + donorOrganizationIds: [], +}; + +export default DonorsContainer; diff --git a/lib/DonorsList/DonorsList.js b/lib/DonorsList/DonorsList.js new file mode 100644 index 00000000..a9855ada --- /dev/null +++ b/lib/DonorsList/DonorsList.js @@ -0,0 +1,165 @@ +import React, { useMemo } from 'react'; +import { + map, + sortBy, +} from 'lodash'; +import PropTypes from 'prop-types'; +import { + FormattedMessage, + useIntl, +} from 'react-intl'; + +import { + Button, + Icon, + MultiColumnList, +} from '@folio/stripes/components'; +import { + Pluggable, + useStripes, +} from '@folio/stripes/core'; + +import { acqRowFormatter } from '../utils'; + +const columnMapping = { + name: , + code: , + unassignDonor: null, +}; + +const visibleColumns = [ + 'name', + 'code', + 'unassignDonor', +]; + +const getResultsFormatter = ({ + intl, + fields, +}) => ({ + name: donor => donor.name, + code: donor => donor.code, + unassignDonor: (donor) => ( + + ), +}); + +const getDonorUrl = (orgId) => { + if (orgId) { + return `/organizations/view/${orgId}`; + } + + return undefined; +}; + +const AddDonorButton = ({ fetchDonors, fields, stripes, name }) => { + const addDonors = (contacts = []) => { + const addedContactIds = new Set(fields.value); + const newContactsIds = map(contacts.filter(({ id }) => !addedContactIds.has(id)), 'id'); + + if (newContactsIds.length) { + fetchDonors([...addedContactIds, ...newContactsIds]); + newContactsIds.forEach(contactId => fields.push(contactId)); + } + }; + + return ( + } + searchButtonStyle="default" + disableRecordCreation + stripes={stripes} + selectVendor={addDonors} + isDonorsEnabled + > + + + + + ); +}; + +AddDonorButton.propTypes = { + fetchDonors: PropTypes.func.isRequired, + fields: PropTypes.object, + stripes: PropTypes.object, + name: PropTypes.string.isRequired, +}; + +const alignRowProps = { alignLastColToEnd: true }; + +const DonorsList = ({ fetchDonors, fields, donorsMap, id }) => { + const intl = useIntl(); + const stripes = useStripes(); + const canViewOrganizations = stripes.hasPerm('ui-organizations.view'); + const donors = (fields.value || []) + .map((contactId, _index) => { + const contact = donorsMap?.[contactId]; + + return { + ...(contact || { isDeleted: true }), + _index, + }; + }); + const contentData = sortBy(donors, [({ lastName }) => lastName?.toLowerCase()]); + + const anchoredRowFormatter = ({ rowProps, ...rest }) => { + return acqRowFormatter({ + ...rest, + rowProps: { + ...rowProps, + to: getDonorUrl(canViewOrganizations && rest.rowData.id), + }, + }); + }; + + const resultsFormatter = useMemo(() => { + return getResultsFormatter({ intl, fields }); + }, [fields, intl]); + + return ( + <> + +
+ + + ); +}; + +DonorsList.propTypes = { + fetchDonors: PropTypes.func.isRequired, + fields: PropTypes.object, + donorsMap: PropTypes.object, + id: PropTypes.string.isRequired, +}; + +export default DonorsList; diff --git a/lib/DonorsList/hooks/index.js b/lib/DonorsList/hooks/index.js new file mode 100644 index 00000000..eed71fe5 --- /dev/null +++ b/lib/DonorsList/hooks/index.js @@ -0,0 +1 @@ +export { useFetchDonors } from './useFetchDonors'; diff --git a/lib/DonorsList/hooks/useFetchDonors/index.js b/lib/DonorsList/hooks/useFetchDonors/index.js new file mode 100644 index 00000000..eed71fe5 --- /dev/null +++ b/lib/DonorsList/hooks/useFetchDonors/index.js @@ -0,0 +1 @@ +export { useFetchDonors } from './useFetchDonors'; diff --git a/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.js b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.js new file mode 100644 index 00000000..ee08a023 --- /dev/null +++ b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.js @@ -0,0 +1,36 @@ +import { useMutation } from 'react-query'; + +import { useOkapiKy } from '@folio/stripes/core'; + +import { VENDORS_API } from '../../../constants'; +import { batchRequest } from '../../../utils'; + +const buildQueryByIds = (itemsChunk) => { + const query = itemsChunk + .map(chunkId => `id==${chunkId}`) + .join(' or '); + + return query || ''; +}; + +export const useFetchDonors = () => { + const ky = useOkapiKy(); + + const { isLoading, mutateAsync } = useMutation( + ({ donorOrganizationIds }) => { + return batchRequest( + ({ params: searchParams }) => ky + .get(VENDORS_API, { searchParams }) + .json() + .then(({ organizations }) => organizations), + donorOrganizationIds, + buildQueryByIds, + ); + }, + ); + + return ({ + fetchDonorsMutation: mutateAsync, + isLoading, + }); +}; diff --git a/lib/DonorsList/index.js b/lib/DonorsList/index.js new file mode 100644 index 00000000..66ae435f --- /dev/null +++ b/lib/DonorsList/index.js @@ -0,0 +1 @@ +export { default as DonorsList } from './DonorsContainer'; diff --git a/lib/index.js b/lib/index.js index ea8509f8..7c0140a3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -16,6 +16,7 @@ export * from './Currency'; export * from './CurrencyExchangeRateFields'; export * from './CurrencySymbol'; export * from './DeleteHoldingsModal'; +export * from './DonorsList'; export * from './DragDropMCL'; export * from './DynamicSelection'; export * from './DynamicSelectionFilter'; diff --git a/translations/stripes-acq-components/en.json b/translations/stripes-acq-components/en.json index 5b2d35a1..6d8cf536 100644 --- a/translations/stripes-acq-components/en.json +++ b/translations/stripes-acq-components/en.json @@ -187,5 +187,8 @@ "acquisition_method.other": "Other", "acquisition_method.purchase": "Purchase", "acquisition_method.purchaseAtVendorSystem": "Purchase at vendor system", - "acquisition_method.technical": "Technical" + "acquisition_method.technical": "Technical", + "donors.button.addDonor": "Add donor", + "donors.column.code": "Code", + "donors.column.name": "Name" } From cb5be471ccd3440d780ce4714ec1279162db94f8 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Tue, 31 Oct 2023 18:46:50 +0500 Subject: [PATCH 02/16] tests: add test coverages --- lib/DonorsList/DonorsContainer.test.js | 93 ++++++++++++++++++++++++++ lib/DonorsList/DonorsList.test.js | 53 +++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 lib/DonorsList/DonorsContainer.test.js create mode 100644 lib/DonorsList/DonorsList.test.js diff --git a/lib/DonorsList/DonorsContainer.test.js b/lib/DonorsList/DonorsContainer.test.js new file mode 100644 index 00000000..9ada4541 --- /dev/null +++ b/lib/DonorsList/DonorsContainer.test.js @@ -0,0 +1,93 @@ +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; + +import stripesFinalForm from '@folio/stripes/final-form'; + +import DonorsContainer from './DonorsContainer'; +import { useFetchDonors } from './hooks'; + +jest.mock('@folio/stripes/components', () => ({ + ...jest.requireActual('@folio/stripes/components'), + Loading: jest.fn(() => 'Loading'), +})); + +jest.mock('./DonorsList', () => jest.fn(({ donorsMap }) => { + if (!Object.values(donorsMap).length) { + return 'stripes-components.tableEmpty'; + } + + return Object.values(donorsMap).map(donor =>
{donor.name}
); +})); + +jest.mock('./hooks', () => ({ + useFetchDonors: jest.fn().mockReturnValue({ + fetchDonorsMutation: jest.fn(), + isLoading: false, + }), +})); + +const defaultProps = { + name: 'donors', + donorOrganizationIds: [], +}; + +const renderForm = (props = {}) => ( +
+ + + +); + +const FormCmpt = stripesFinalForm({})(renderForm); + +const renderComponent = (props = {}) => (render( + + { }} {...props} /> + , +)); + +describe('DonorsContainer', () => { + beforeEach(() => { + useFetchDonors.mockClear().mockReturnValue({ + fetchDonorsMutation: jest.fn(), + isLoading: false, + }); + }); + + it('should render component', () => { + renderComponent(); + + expect(screen.getByText('stripes-components.tableEmpty')).toBeDefined(); + }); + + it('should render Loading component', () => { + useFetchDonors.mockClear().mockReturnValue({ + fetchDonorsMutation: jest.fn(), + isLoading: true, + }); + + renderComponent(); + + expect(screen.getByText('Loading')).toBeDefined(); + }); + + it('should call `fetchDonorsMutation` with `donorOrganizationIds`', () => { + const mockData = [{ name: 'Amazon', code: 'AMAZ', id: '1' }]; + const fetchDonorsMutationMock = jest.fn().mockReturnValue({ + then: (cb) => cb(mockData), + }); + + useFetchDonors.mockClear().mockReturnValue({ + fetchDonorsMutation: fetchDonorsMutationMock, + isLoading: false, + }); + + renderComponent({ donorOrganizationIds: ['1'] }); + + expect(fetchDonorsMutationMock).toHaveBeenCalled(); + expect(screen.getByText(mockData[0].name)).toBeDefined(); + }); +}); diff --git a/lib/DonorsList/DonorsList.test.js b/lib/DonorsList/DonorsList.test.js new file mode 100644 index 00000000..9a2d28d8 --- /dev/null +++ b/lib/DonorsList/DonorsList.test.js @@ -0,0 +1,53 @@ +import { render, screen } from '@testing-library/react'; +import { MemoryRouter } from 'react-router-dom'; + +import DonorsList from './DonorsList'; + +const mockFetchDonors = jest.fn(); + +const defaultProps = { + fetchDonors: mockFetchDonors, + fields: {}, + donorsMap: {}, + id: 'donors', +}; + +const wrapper = ({ children }) => ( + + {children} + +); + +const renderComponent = (props = {}) => (render( + , + { wrapper }, +)); + +describe('DonorsList', () => { + it('should render component', () => { + renderComponent(); + + expect(screen.getByText('stripes-components.tableEmpty')).toBeDefined(); + }); + + it('should render the list of donor organizations', () => { + renderComponent({ + fields: { + value: [ + '1', + '2', + ], + }, + donorsMap: { + 1: { id: '1', name: 'Amazon' }, + 2: { id: '2', name: 'Google' }, + }, + }); + + expect(screen.getByText('Amazon')).toBeDefined(); + expect(screen.getByText('Google')).toBeDefined(); + }); +}); From 407e3a1842698474f532f77c62f9121acef3084d Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Tue, 31 Oct 2023 20:07:25 +0500 Subject: [PATCH 03/16] tests: add test coverage and Changelog.md --- CHANGELOG.md | 1 + .../useFetchDonors/useFetchDonors.test.js | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e2e1c706..abaf8ee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Sort the list of countries based on the current locale. Refs UISACQCOMP-164. * Add `inputType` prop to ``. Refs UISACQCOMP-165. +* View the list of donors. Refs UISACQCOMP-166. ## [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) diff --git a/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js new file mode 100644 index 00000000..c3494842 --- /dev/null +++ b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js @@ -0,0 +1,49 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { QueryClient, QueryClientProvider } from 'react-query'; + +import { useOkapiKy } from '@folio/stripes/core'; + +import { useFetchDonors } from './useFetchDonors'; + +jest.mock('@folio/stripes/core', () => ({ + ...jest.requireActual('@folio/stripes/core'), + useOkapiKy: jest.fn(), +})); + +const queryClient = new QueryClient(); + +const wrapper = ({ children }) => ( + + {children} + +); + +const org = { id: 'orgId', name: 'VENDOR' }; + +const getMock = jest.fn().mockReturnValue({ + json: () => Promise.resolve(({ organizations: [org], totalRecords: 1 })), +}); + +describe('useDonors', () => { + beforeEach(() => { + getMock.mockClear(); + + useOkapiKy + .mockClear() + .mockReturnValue({ + get: getMock, + }); + }); + + it('should make a get a request with default search params', async () => { + const { result, waitFor } = renderHook(() => useFetchDonors(), { wrapper }); + + await result.current.fetchDonorsMutation({ donorOrganizationIds: ['orgId'] }); + await waitFor(() => !result.current.isLoading); + + expect(getMock).toHaveBeenCalledWith( + 'organizations/organizations', + { 'searchParams': { 'limit': 1000, 'query': 'id==orgId' } }, + ); + }); +}); From 9afb1339717eaec186fcdaba03e02f39668b747b Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Tue, 31 Oct 2023 23:09:22 +0500 Subject: [PATCH 04/16] refactor: change the order of import files --- lib/DonorsList/DonorsContainer.test.js | 4 ++-- lib/DonorsList/DonorsList.test.js | 2 +- lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/DonorsList/DonorsContainer.test.js b/lib/DonorsList/DonorsContainer.test.js index 9ada4541..9832c0a9 100644 --- a/lib/DonorsList/DonorsContainer.test.js +++ b/lib/DonorsList/DonorsContainer.test.js @@ -1,5 +1,5 @@ -import { render, screen } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; +import { render, screen } from '@testing-library/react'; import stripesFinalForm from '@folio/stripes/final-form'; @@ -16,7 +16,7 @@ jest.mock('./DonorsList', () => jest.fn(({ donorsMap }) => { return 'stripes-components.tableEmpty'; } - return Object.values(donorsMap).map(donor =>
{donor.name}
); + return Object.values(donorsMap).map(({ name }) =>
{name}
); })); jest.mock('./hooks', () => ({ diff --git a/lib/DonorsList/DonorsList.test.js b/lib/DonorsList/DonorsList.test.js index 9a2d28d8..c64b15ba 100644 --- a/lib/DonorsList/DonorsList.test.js +++ b/lib/DonorsList/DonorsList.test.js @@ -1,5 +1,5 @@ -import { render, screen } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; +import { render, screen } from '@testing-library/react'; import DonorsList from './DonorsList'; diff --git a/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js index c3494842..7eef974f 100644 --- a/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js +++ b/lib/DonorsList/hooks/useFetchDonors/useFetchDonors.test.js @@ -1,5 +1,8 @@ +import { + QueryClient, + QueryClientProvider, +} from 'react-query'; import { renderHook } from '@testing-library/react-hooks'; -import { QueryClient, QueryClientProvider } from 'react-query'; import { useOkapiKy } from '@folio/stripes/core'; From acb730f9b0eef8c432dfc6f05b991d2187085710 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Wed, 1 Nov 2023 18:13:13 +0500 Subject: [PATCH 05/16] add column width for better table view --- lib/DonorsList/DonorsList.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/DonorsList/DonorsList.js b/lib/DonorsList/DonorsList.js index a9855ada..2b005753 100644 --- a/lib/DonorsList/DonorsList.js +++ b/lib/DonorsList/DonorsList.js @@ -103,7 +103,11 @@ AddDonorButton.propTypes = { }; const alignRowProps = { alignLastColToEnd: true }; - +const columnWidths = { + name: '45%', + code: '45%', + unassignDonor: '10%', +}; const DonorsList = ({ fetchDonors, fields, donorsMap, id }) => { const intl = useIntl(); const stripes = useStripes(); @@ -143,6 +147,7 @@ const DonorsList = ({ fetchDonors, fields, donorsMap, id }) => { rowFormatter={anchoredRowFormatter} rowProps={alignRowProps} visibleColumns={visibleColumns} + columnWidths={columnWidths} />
Date: Thu, 2 Nov 2023 09:44:32 +0500 Subject: [PATCH 06/16] refactor: add config properties for plugin to implement donors --- lib/DonorsList/AddDonorButton.js | 60 +++++++++++++++++ lib/DonorsList/DonorsList.js | 73 ++------------------- lib/DonorsList/constants.js | 60 +++++++++++++++++ translations/stripes-acq-components/en.json | 5 +- 4 files changed, 129 insertions(+), 69 deletions(-) create mode 100644 lib/DonorsList/AddDonorButton.js create mode 100644 lib/DonorsList/constants.js diff --git a/lib/DonorsList/AddDonorButton.js b/lib/DonorsList/AddDonorButton.js new file mode 100644 index 00000000..1a1a8493 --- /dev/null +++ b/lib/DonorsList/AddDonorButton.js @@ -0,0 +1,60 @@ +import { map } from 'lodash'; +import PropTypes from 'prop-types'; +import { FormattedMessage } from 'react-intl'; + +import { Pluggable } from '@folio/stripes/core'; + +import { + initialFilters, + modalLabel, + pluginVisibleColumns, + resultsPaneTitle, + searchableIndexes, + visibleFilters, +} from './constants'; + +const AddDonorButton = ({ fetchDonors, fields, stripes, name }) => { + const addDonors = (donors = []) => { + const addedDonorIds = new Set(fields.value); + const newDonorsIds = map(donors.filter(({ id }) => !addedDonorIds.has(id)), 'id'); + + if (newDonorsIds.length) { + fetchDonors([...addedDonorIds, ...newDonorsIds]); + newDonorsIds.forEach(contactId => fields.push(contactId)); + } + }; + + return ( + } + searchButtonStyle="default" + disableRecordCreation + stripes={stripes} + selectVendor={addDonors} + modalLabel={modalLabel} + resultsPaneTitle={resultsPaneTitle} + visibleColumns={pluginVisibleColumns} + initialFilters={initialFilters} + searchableIndexes={searchableIndexes} + visibleFilters={visibleFilters} + isMultiSelect + > + + + + + ); +}; + +AddDonorButton.propTypes = { + fetchDonors: PropTypes.func.isRequired, + fields: PropTypes.object, + stripes: PropTypes.object, + name: PropTypes.string.isRequired, +}; + +export default AddDonorButton; diff --git a/lib/DonorsList/DonorsList.js b/lib/DonorsList/DonorsList.js index 2b005753..18008cd0 100644 --- a/lib/DonorsList/DonorsList.js +++ b/lib/DonorsList/DonorsList.js @@ -1,37 +1,18 @@ import React, { useMemo } from 'react'; -import { - map, - sortBy, -} from 'lodash'; +import { sortBy } from 'lodash'; import PropTypes from 'prop-types'; -import { - FormattedMessage, - useIntl, -} from 'react-intl'; +import { useIntl } from 'react-intl'; import { Button, Icon, MultiColumnList, } from '@folio/stripes/components'; -import { - Pluggable, - useStripes, -} from '@folio/stripes/core'; +import { useStripes } from '@folio/stripes/core'; import { acqRowFormatter } from '../utils'; - -const columnMapping = { - name: , - code: , - unassignDonor: null, -}; - -const visibleColumns = [ - 'name', - 'code', - 'unassignDonor', -]; +import AddDonorButton from './AddDonorButton'; +import { alignRowProps, columnMapping, columnWidths, visibleColumns } from './constants'; const getResultsFormatter = ({ intl, @@ -64,50 +45,6 @@ const getDonorUrl = (orgId) => { return undefined; }; -const AddDonorButton = ({ fetchDonors, fields, stripes, name }) => { - const addDonors = (contacts = []) => { - const addedContactIds = new Set(fields.value); - const newContactsIds = map(contacts.filter(({ id }) => !addedContactIds.has(id)), 'id'); - - if (newContactsIds.length) { - fetchDonors([...addedContactIds, ...newContactsIds]); - newContactsIds.forEach(contactId => fields.push(contactId)); - } - }; - - return ( - } - searchButtonStyle="default" - disableRecordCreation - stripes={stripes} - selectVendor={addDonors} - isDonorsEnabled - > - - - - - ); -}; - -AddDonorButton.propTypes = { - fetchDonors: PropTypes.func.isRequired, - fields: PropTypes.object, - stripes: PropTypes.object, - name: PropTypes.string.isRequired, -}; - -const alignRowProps = { alignLastColToEnd: true }; -const columnWidths = { - name: '45%', - code: '45%', - unassignDonor: '10%', -}; const DonorsList = ({ fetchDonors, fields, donorsMap, id }) => { const intl = useIntl(); const stripes = useStripes(); diff --git a/lib/DonorsList/constants.js b/lib/DonorsList/constants.js new file mode 100644 index 00000000..83dc99ea --- /dev/null +++ b/lib/DonorsList/constants.js @@ -0,0 +1,60 @@ +import { FormattedMessage } from 'react-intl'; + +export const columnMapping = { + name: , + code: , + unassignDonor: null, +}; + +export const visibleColumns = [ + 'name', + 'code', + 'unassignDonor', +]; + +export const alignRowProps = { alignLastColToEnd: true }; + +export const columnWidths = { + name: '45%', + code: '45%', + unassignDonor: '10%', +}; + +export const modalLabel = ; +export const resultsPaneTitle = ; + +export const pluginVisibleColumns = ['name', 'code']; + +export const DONORS_SORT_MAP = { + name: 'name', + code: 'code', +}; + +const ORGANIZATION_STATUS = { + active: 'Active', + inactive: 'Inactive', + pending: 'Pending', +}; + +const FILTERS = { + IS_VENDOR: 'isVendor', + STATUS: 'status', + TAGS: 'tags', + TYPES: 'organizationTypes', +}; + +export const visibleFilters = [ + FILTERS.IS_VENDOR, + FILTERS.TAGS, + FILTERS.TYPES, +]; + +export const initialFilters = { + [FILTERS.IS_DONOR]: ['true'], + [FILTERS.STATUS]: [ORGANIZATION_STATUS.active], +}; + +export const searchableIndexes = pluginVisibleColumns.map(column => ({ + labelId: `ui-organizations.search.${column}`, + value: column, +})); diff --git a/translations/stripes-acq-components/en.json b/translations/stripes-acq-components/en.json index 6d8cf536..cb8b9d23 100644 --- a/translations/stripes-acq-components/en.json +++ b/translations/stripes-acq-components/en.json @@ -190,5 +190,8 @@ "acquisition_method.technical": "Technical", "donors.button.addDonor": "Add donor", "donors.column.code": "Code", - "donors.column.name": "Name" + "donors.column.name": "Name", + "donors.modal.title": "Add donors", + "donors.modal.resultsTitle": "Donors", + "donors.noFindOrganizationPlugin": "no find-organization plugin" } From f12b1bcdcc3238d89f75f18c7de7628200251a14 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Thu, 2 Nov 2023 15:29:54 +0500 Subject: [PATCH 07/16] fix: add missing IS_DONOR filter prop --- lib/DonorsList/constants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/DonorsList/constants.js b/lib/DonorsList/constants.js index 83dc99ea..2fb6138c 100644 --- a/lib/DonorsList/constants.js +++ b/lib/DonorsList/constants.js @@ -38,6 +38,7 @@ const ORGANIZATION_STATUS = { const FILTERS = { IS_VENDOR: 'isVendor', + IS_DONOR: 'isDonor', STATUS: 'status', TAGS: 'tags', TYPES: 'organizationTypes', From e54369b45bc571cb5dd24b789388e46b0adda502 Mon Sep 17 00:00:00 2001 From: Alisher Musurmonov Date: Thu, 2 Nov 2023 18:38:56 +0500 Subject: [PATCH 08/16] improve code quality regarding to the comments --- lib/DonorsList/DonorsList.js | 48 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/lib/DonorsList/DonorsList.js b/lib/DonorsList/DonorsList.js index 18008cd0..78427b10 100644 --- a/lib/DonorsList/DonorsList.js +++ b/lib/DonorsList/DonorsList.js @@ -7,25 +7,38 @@ import { Button, Icon, MultiColumnList, + TextLink, } from '@folio/stripes/components'; import { useStripes } from '@folio/stripes/core'; -import { acqRowFormatter } from '../utils'; import AddDonorButton from './AddDonorButton'; -import { alignRowProps, columnMapping, columnWidths, visibleColumns } from './constants'; +import { + alignRowProps, + columnMapping, + columnWidths, + visibleColumns, +} from './constants'; + +const getDonorUrl = (orgId) => { + if (orgId) { + return `/organizations/view/${orgId}`; + } + + return undefined; +}; const getResultsFormatter = ({ - intl, + canViewOrganizations, fields, + intl, }) => ({ - name: donor => donor.name, + name: donor => {donor.name}, code: donor => donor.code, - unassignDonor: (donor) => ( + unassignDonor: donor => ( + + ); + }), +})); + const mockOnAddDonors = jest.fn(); const defaultProps = { onAddDonors: mockOnAddDonors, - fields: {}, - stripes: {}, + fields: { + name: 'donors', + }, name: 'donors', }; -const renderComponent = (props = {}) => (render( - , +const renderComponent = (props = defaultProps) => (render( + , )); describe('AddDonorButton', () => { - it('should render component', () => { - renderComponent(); + it('should render component', async () => { + renderComponent({ + fields: { + name: 'donors', + push: jest.fn(), + }, + name: 'donors', + onAddDonors: mockOnAddDonors, + }); + + const addDonorsButton = screen.getByText('Add donor'); + + expect(addDonorsButton).toBeDefined(); + + await user.click(addDonorsButton); - expect(screen.getByText('stripes-acq-components.donors.noFindOrganizationPlugin')).toBeDefined(); + expect(mockOnAddDonors).toHaveBeenCalledWith([mockVendorData.id]); }); });