Skip to content

Commit

Permalink
UISACQCOMP-166: configure the plugin via props
Browse files Browse the repository at this point in the history
  • Loading branch information
alisher-epam committed Nov 7, 2023
1 parent 5bbcf17 commit a4193de
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 69 deletions.
26 changes: 23 additions & 3 deletions lib/DonorsList/AddDonorButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ import {
visibleFilters,
} from './constants';

const AddDonorButton = ({ onAddDonors, fields, stripes, name }) => {
const AddDonorButton = ({
fields,
name,
onAddDonors,
searchLabel,
showTriggerButton,
stripes,
visibleColumns,
}) => {
const addDonors = (donors = []) => {
const addedDonorIds = new Set(fields.value);
const newDonorsIds = map(donors.filter(({ id }) => !addedDonorIds.has(id)), 'id');
Expand All @@ -24,20 +32,24 @@ const AddDonorButton = ({ onAddDonors, fields, stripes, name }) => {
}
};

if (!showTriggerButton) {
return null;
}

return (
<Pluggable
id={`${name}-plugin`}
aria-haspopup="true"
type="find-organization"
dataKey="organization"
searchLabel={<FormattedMessage id="stripes-acq-components.donors.button.addDonor" />}
searchLabel={searchLabel}
searchButtonStyle="default"
disableRecordCreation
stripes={stripes}
selectVendor={addDonors}
modalLabel={modalLabel}
resultsPaneTitle={resultsPaneTitle}
visibleColumns={pluginVisibleColumns}
visibleColumns={visibleColumns}
initialFilters={initialFilters}
searchableIndexes={searchableIndexes}
visibleFilters={visibleFilters}
Expand All @@ -55,6 +67,14 @@ AddDonorButton.propTypes = {
fields: PropTypes.object,
stripes: PropTypes.object,
name: PropTypes.string.isRequired,
showTriggerButton: PropTypes.bool,
searchLabel: PropTypes.node,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

AddDonorButton.defaultProps = {
showTriggerButton: true,
searchLabel: <FormattedMessage id="stripes-acq-components.donors.button.addDonor" />,
visibleColumns: pluginVisibleColumns,
};
export default AddDonorButton;
82 changes: 46 additions & 36 deletions lib/DonorsList/DonorsContainer.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,62 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { FieldArray } from 'react-final-form-arrays';

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

import AddDonorButton from './AddDonorButton';
import DonorsList from './DonorsList';
import { useFetchDonors } from './hooks';

function DonorsContainer({ name, donorOrganizationIds }) {
const [donorIds, setDonorIds] = useState(donorOrganizationIds);
const { donors, isLoading } = useFetchDonors(donorIds);

const donorsMap = donors.reduce((acc, contact) => {
acc[contact.id] = contact;

return acc;
}, {});

if (isLoading) {
return <Loading />;
}
import { defaultVisibleColumns } from './constants';

function DonorsContainer({
donorsMap,
fields,
id,
setDonorIds,
showTriggerButton,
visibleColumns,
...rest
}) {
const stripes = useStripes();

return (
<Row>
<Col xs={12}>
<FieldArray
name={name}
id={name}
component={DonorsList}
setDonorIds={setDonorIds}
donorsMap={donorsMap}
/>
</Col>
</Row>
<>
<DonorsList
fields={fields}
donorsMap={donorsMap}
id={id}
stripes={stripes}
visibleColumns={visibleColumns}
/>
<br />
{
showTriggerButton && (
<AddDonorButton
onAddDonors={setDonorIds}
fields={fields}
stripes={stripes}
name={id}
{...rest}
/>
)
}
</>
);
}

DonorsContainer.propTypes = {
name: PropTypes.string.isRequired,
donorOrganizationIds: PropTypes.arrayOf(PropTypes.string),
columnWidths: PropTypes.object,
donorsMap: PropTypes.object,
fields: PropTypes.object,
formatter: PropTypes.object,
id: PropTypes.string.isRequired,
searchLabel: PropTypes.node,
setDonorIds: PropTypes.func.isRequired,
showTriggerButton: PropTypes.bool,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

DonorsContainer.defaultProps = {
donorOrganizationIds: [],
showTriggerButton: true,
visibleColumns: defaultVisibleColumns,
};

export default DonorsContainer;
56 changes: 56 additions & 0 deletions lib/DonorsList/DonorsForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { FieldArray } from 'react-final-form-arrays';

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

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

function DonorsForm({ name, donorOrganizationIds, ...rest }) {
const [donorIds, setDonorIds] = useState(donorOrganizationIds);
const { donors, isLoading } = useFetchDonors(donorIds);

const donorsMap = donors.reduce((acc, contact) => {
acc[contact.id] = contact;

return acc;
}, {});

if (isLoading) {
return <Loading />;
}

return (
<Row>
<Col xs={12}>
<FieldArray
name={name}
id={name}
component={DonorsContainer}
setDonorIds={setDonorIds}
donorsMap={donorsMap}
{...rest}
/>
</Col>
</Row>
);
}

DonorsForm.propTypes = {
donorOrganizationIds: PropTypes.arrayOf(PropTypes.string),
name: PropTypes.string.isRequired,
searchLabel: PropTypes.node,
showTriggerButton: PropTypes.bool,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

DonorsForm.defaultProps = {
donorOrganizationIds: [],
};

export default DonorsForm;
89 changes: 89 additions & 0 deletions lib/DonorsList/DonorsForm.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';

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

import DonorsForm from './DonorsForm';
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(({ name }) => <div key={name}>{name}</div>);
}));

jest.mock('./hooks', () => ({
useFetchDonors: jest.fn().mockReturnValue({
donors: [],
isLoading: false,
}),
}));

const defaultProps = {
name: 'donors',
donorOrganizationIds: [],
};

const renderForm = (props = {}) => (
<form>
<DonorsForm
{...defaultProps}
{...props}
/>
<button type="submit">Submit</button>
</form>
);

const FormCmpt = stripesFinalForm({})(renderForm);

const renderComponent = (props = {}) => (render(
<MemoryRouter>
<FormCmpt onSubmit={() => { }} {...props} />
</MemoryRouter>,
));

describe('DonorsForm', () => {
beforeEach(() => {
useFetchDonors.mockClear().mockReturnValue({
donors: [],
isLoading: false,
});
});

it('should render component', () => {
renderComponent();

expect(screen.getByText('stripes-components.tableEmpty')).toBeDefined();
});

it('should render Loading component', () => {
useFetchDonors.mockClear().mockReturnValue({
donors: [],
isLoading: true,
});

renderComponent();

expect(screen.getByText('Loading')).toBeDefined();
});

it('should call `useFetchDonors` with `donorOrganizationIds`', () => {
const mockData = [{ name: 'Amazon', code: 'AMAZ', id: '1' }];

useFetchDonors.mockClear().mockReturnValue({
donors: mockData,
isLoading: false,
});

renderComponent({ donorOrganizationIds: ['1'] });

expect(screen.getByText(mockData[0].name)).toBeDefined();
});
});
59 changes: 33 additions & 26 deletions lib/DonorsList/DonorsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import {
MultiColumnList,
TextLink,
} from '@folio/stripes/components';
import { useStripes } from '@folio/stripes/core';

import AddDonorButton from './AddDonorButton';
import {
alignRowProps,
columnMapping,
columnWidths,
visibleColumns,
defaultColumnMapping,
defaultColumnWidths,
defaultVisibleColumns,
} from './constants';

const getDonorUrl = (orgId) => {
Expand Down Expand Up @@ -50,9 +48,17 @@ const getResultsFormatter = ({
),
});

const DonorsList = ({ setDonorIds, fields, donorsMap, id }) => {
const DonorsList = ({
columnMapping,
columnWidths,
donorsMap,
fields,
formatter,
id,
stripes,
visibleColumns,
}) => {
const intl = useIntl();
const stripes = useStripes();
const canViewOrganizations = stripes.hasPerm('ui-organizations.view');

const donors = useMemo(() => (fields.value || [])
Expand All @@ -72,32 +78,33 @@ const DonorsList = ({ setDonorIds, fields, donorsMap, id }) => {
}, [canViewOrganizations, fields, intl]);

return (
<>
<MultiColumnList
id={id}
columnMapping={columnMapping}
contentData={contentData}
formatter={resultsFormatter}
rowProps={alignRowProps}
visibleColumns={visibleColumns}
columnWidths={columnWidths}
/>
<br />
<AddDonorButton
onAddDonors={setDonorIds}
fields={fields}
stripes={stripes}
name={id}
/>
</>
<MultiColumnList
id={id}
columnMapping={columnMapping}
contentData={contentData}
formatter={formatter || resultsFormatter}
rowProps={alignRowProps}
visibleColumns={visibleColumns}
columnWidths={columnWidths}
/>
);
};

DonorsList.propTypes = {
setDonorIds: PropTypes.func.isRequired,
fields: PropTypes.object,
donorsMap: PropTypes.object,
id: PropTypes.string.isRequired,
stripes: PropTypes.object,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
formatter: PropTypes.object,
columnWidths: PropTypes.object,
columnMapping: PropTypes.object,
};

DonorsList.defaultProps = {
columnMapping: defaultColumnMapping,
columnWidths: defaultColumnWidths,
visibleColumns: defaultVisibleColumns,
};

export default DonorsList;
Loading

0 comments on commit a4193de

Please sign in to comment.