Skip to content

Commit

Permalink
refactor: move logic to component container
Browse files Browse the repository at this point in the history
  • Loading branch information
alisher-epam committed Nov 7, 2023
1 parent db1007b commit ddbc2b2
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 113 deletions.
69 changes: 56 additions & 13 deletions lib/DonorsList/DonorsContainer.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,82 @@
import { map, sortBy } from 'lodash';
import PropTypes from 'prop-types';
import { useMemo } from 'react';
import { useIntl } from 'react-intl';

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

import AddDonorButton from './AddDonorButton';
import DonorsList from './DonorsList';
import { defaultVisibleColumns } from './constants';
import DonorsList from './DonorsList';
import DonorsLookup from './DonorsLookup';
import { getResultsFormatter } from './utils';

function DonorsContainer({
donorsMap,
columnMapping,
columnWidths,
donors,
fields,
formatter,
id,
setDonorIds,
searchLabel,
showTriggerButton,
visibleColumns,
...rest
}) {
const stripes = useStripes();
const intl = useIntl();
const canViewOrganizations = stripes.hasPerm('ui-organizations.view');

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

return acc;
}, {});

const listOfDonors = useMemo(() => (fields.value || [])
.map((contactId, _index) => {
const contact = donorsMap?.[contactId];

return {
...(contact || { isDeleted: true }),
_index,
};
}), [donorsMap, fields.value]);

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

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

const onAddDonors = (values = []) => {
const addedDonorIds = new Set(fields.value);
const newDonorsIds = map(values.filter(({ id: donorId }) => !addedDonorIds.has(donorId)), 'id');

if (newDonorsIds.length) {
setDonorIds([...addedDonorIds, ...newDonorsIds]);
newDonorsIds.forEach(contactId => fields.push(contactId));
}
};

return (
<>
<DonorsList
fields={fields}
donorsMap={donorsMap}
id={id}
stripes={stripes}
visibleColumns={visibleColumns}
contentData={contentData}
formatter={resultsFormatter}
columnMapping={columnMapping}
columnWidths={columnWidths}
/>
<br />
{
showTriggerButton && (
<AddDonorButton
onAddDonors={setDonorIds}
fields={fields}
stripes={stripes}
<DonorsLookup
onAddDonors={onAddDonors}
name={id}
{...rest}
searchLabel={searchLabel}
showTriggerButton={showTriggerButton}
visibleColumns={visibleColumns}
/>
)
}
Expand All @@ -44,7 +86,8 @@ function DonorsContainer({

DonorsContainer.propTypes = {
columnWidths: PropTypes.object,
donorsMap: PropTypes.object,
columnMapping: PropTypes.object,
donors: PropTypes.arrayOf(PropTypes.object),
fields: PropTypes.object,
formatter: PropTypes.object,
id: PropTypes.string.isRequired,
Expand Down
18 changes: 10 additions & 8 deletions lib/DonorsList/DonorsForm.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { FieldArray } from 'react-final-form-arrays';
import { useState } from 'react';

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

import {
defaultColumnMapping,
defaultColumnWidths,
} from './constants';
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 />;
}
Expand All @@ -33,7 +31,7 @@ function DonorsForm({ name, donorOrganizationIds, ...rest }) {
id={name}
component={DonorsContainer}
setDonorIds={setDonorIds}
donorsMap={donorsMap}
donors={donors}
{...rest}
/>
</Col>
Expand All @@ -42,6 +40,8 @@ function DonorsForm({ name, donorOrganizationIds, ...rest }) {
}

DonorsForm.propTypes = {
columnMapping: PropTypes.object,
columnWidths: PropTypes.object,
donorOrganizationIds: PropTypes.arrayOf(PropTypes.string),
name: PropTypes.string.isRequired,
searchLabel: PropTypes.node,
Expand All @@ -51,6 +51,8 @@ DonorsForm.propTypes = {

DonorsForm.defaultProps = {
donorOrganizationIds: [],
columnMapping: defaultColumnMapping,
columnWidths: defaultColumnWidths,
};

export default DonorsForm;
76 changes: 7 additions & 69 deletions lib/DonorsList/DonorsList.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import React, { useMemo } from 'react';
import { sortBy } from 'lodash';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';

import {
Button,
Icon,
MultiColumnList,
TextLink,
} from '@folio/stripes/components';
import { MultiColumnList } from '@folio/stripes/components';

import {
alignRowProps,
Expand All @@ -17,72 +9,20 @@ import {
defaultVisibleColumns,
} from './constants';

const getDonorUrl = (orgId) => {
if (orgId) {
return `/organizations/view/${orgId}`;
}

return undefined;
};

const getResultsFormatter = ({
canViewOrganizations,
fields,
intl,
}) => ({
name: donor => <TextLink to={getDonorUrl(canViewOrganizations && donor.id)}>{donor.name}</TextLink>,
code: donor => donor.code,
unassignDonor: donor => (
<Button
align="end"
aria-label={intl.formatMessage({ id: 'stripes-acq-components.donors.button.unassign' })}
buttonStyle="fieldControl"
type="button"
onClick={(e) => {
e.preventDefault();
fields.remove(donor._index);
}}
>
<Icon icon="times-circle" />
</Button>
),
});

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

const donors = useMemo(() => (fields.value || [])
.map((contactId, _index) => {
const contact = donorsMap?.[contactId];

return {
...(contact || { isDeleted: true }),
_index,
};
}), [donorsMap, fields.value]);

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

const resultsFormatter = useMemo(() => {
return getResultsFormatter({ intl, fields, canViewOrganizations });
}, [canViewOrganizations, fields, intl]);

return (
<MultiColumnList
id={id}
columnMapping={columnMapping}
contentData={contentData}
formatter={formatter || resultsFormatter}
formatter={formatter}
rowProps={alignRowProps}
visibleColumns={visibleColumns}
columnWidths={columnWidths}
Expand All @@ -91,14 +31,12 @@ const DonorsList = ({
};

DonorsList.propTypes = {
fields: PropTypes.object,
donorsMap: PropTypes.object,
columnMapping: PropTypes.object,
columnWidths: PropTypes.object,
contentData: PropTypes.arrayOf(PropTypes.object),
formatter: 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 = {
Expand Down
31 changes: 11 additions & 20 deletions lib/DonorsList/AddDonorButton.js → lib/DonorsList/DonorsLookup.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { map } from 'lodash';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';

import { Pluggable } from '@folio/stripes/core';
import {
Pluggable,
useStripes,
} from '@folio/stripes/core';

import {
initialFilters,
Expand All @@ -13,24 +15,14 @@ import {
visibleFilters,
} from './constants';

const AddDonorButton = ({
fields,
const DonorsLookup = ({
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');

if (newDonorsIds.length) {
onAddDonors([...addedDonorIds, ...newDonorsIds]);
newDonorsIds.forEach(contactId => fields.push(contactId));
}
};
const stripes = useStripes();

if (!showTriggerButton) {
return null;
Expand All @@ -46,7 +38,7 @@ const AddDonorButton = ({
searchButtonStyle="default"
disableRecordCreation
stripes={stripes}
selectVendor={addDonors}
selectVendor={onAddDonors}
modalLabel={modalLabel}
resultsPaneTitle={resultsPaneTitle}
visibleColumns={visibleColumns}
Expand All @@ -62,19 +54,18 @@ const AddDonorButton = ({
);
};

AddDonorButton.propTypes = {
DonorsLookup.propTypes = {
onAddDonors: PropTypes.func.isRequired,
fields: PropTypes.object,
stripes: PropTypes.object,
name: PropTypes.string.isRequired,
showTriggerButton: PropTypes.bool,
searchLabel: PropTypes.node,
visibleColumns: PropTypes.arrayOf(PropTypes.string),
};

AddDonorButton.defaultProps = {
DonorsLookup.defaultProps = {
showTriggerButton: true,
searchLabel: <FormattedMessage id="stripes-acq-components.donors.button.addDonor" />,
visibleColumns: pluginVisibleColumns,
};
export default AddDonorButton;

export default DonorsLookup;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render, screen } from '@testing-library/react';
import user from '@testing-library/user-event';

import AddDonorButton from './AddDonorButton';
import DonorsLookup from './DonorsLookup';

const mockVendorData = { id: '1', name: 'Amazon' };

Expand Down Expand Up @@ -34,10 +34,10 @@ const defaultProps = {
};

const renderComponent = (props = defaultProps) => (render(
<AddDonorButton {...props} />,
<DonorsLookup {...props} />,
));

describe('AddDonorButton', () => {
describe('DonorsLookup', () => {
it('should render component', async () => {
renderComponent({
fields: {
Expand Down
Loading

0 comments on commit ddbc2b2

Please sign in to comment.