-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UISACQCOMP-166: configure the plugin via props (#726)
* UISACQCOMP-166: configure the plugin via props * refactor: move logic to component container * test: fix failing tests * test: add test cases * refactor: change component name * remove isRequired attribute from name prop * refactor: default props * refactor: add default formatter * change default export to named export * remove default formatter * update DonorsList with providing default formatter * fix formatter
- Loading branch information
1 parent
0b6d10c
commit be0e6f9
Showing
20 changed files
with
424 additions
and
207 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
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 { defaultVisibleColumns } from './constants'; | ||
import { DonorsList } from './DonorsList'; | ||
import { DonorsLookup } from './DonorsLookup'; | ||
import { | ||
getDonorsListFormatter, | ||
getUnAssignDonorFormatter, | ||
} from './utils'; | ||
|
||
export function DonorsContainer({ | ||
columnMapping, | ||
columnWidths, | ||
donors, | ||
fields, | ||
formatter, | ||
id, | ||
setDonorIds, | ||
searchLabel, | ||
showTriggerButton, | ||
visibleColumns, | ||
}) { | ||
const stripes = useStripes(); | ||
const intl = useIntl(); | ||
const canViewOrganizations = stripes.hasPerm('ui-organizations.view'); | ||
|
||
const donorsMap = useMemo(() => { | ||
return donors.reduce((acc, contact) => { | ||
acc[contact.id] = contact; | ||
|
||
return acc; | ||
}, {}); | ||
}, [donors]); | ||
|
||
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(() => { | ||
const defaultFormatter = formatter || getDonorsListFormatter({ intl, fields, canViewOrganizations }); | ||
|
||
if (visibleColumns.includes('unassignDonor')) { | ||
return { | ||
...getUnAssignDonorFormatter({ intl, fields }), | ||
...defaultFormatter, | ||
}; | ||
} | ||
|
||
return defaultFormatter; | ||
}, [canViewOrganizations, fields, formatter, intl, visibleColumns]); | ||
|
||
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 | ||
id={id} | ||
visibleColumns={visibleColumns} | ||
contentData={contentData} | ||
formatter={resultsFormatter} | ||
columnMapping={columnMapping} | ||
columnWidths={columnWidths} | ||
/> | ||
<br /> | ||
{ | ||
showTriggerButton && ( | ||
<DonorsLookup | ||
onAddDonors={onAddDonors} | ||
name={id} | ||
searchLabel={searchLabel} | ||
visibleColumns={visibleColumns} | ||
/> | ||
) | ||
} | ||
</> | ||
); | ||
} | ||
|
||
DonorsContainer.propTypes = { | ||
columnWidths: PropTypes.object, | ||
columnMapping: PropTypes.object, | ||
donors: PropTypes.arrayOf(PropTypes.object), | ||
fields: PropTypes.object, | ||
formatter: PropTypes.object, | ||
id: PropTypes.string, | ||
searchLabel: PropTypes.node, | ||
setDonorIds: PropTypes.func.isRequired, | ||
showTriggerButton: PropTypes.bool, | ||
visibleColumns: PropTypes.arrayOf(PropTypes.string), | ||
}; | ||
|
||
DonorsContainer.defaultProps = { | ||
showTriggerButton: true, | ||
visibleColumns: defaultVisibleColumns, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
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 { DonorsContainer } from './DonorsContainer'; | ||
import { useFetchDonors } from './hooks'; | ||
|
||
const mockVendor = { id: '1', name: 'Amazon' }; | ||
|
||
jest.mock('./DonorsList', () => ({ | ||
DonorsList: jest.fn(({ contentData }) => { | ||
return ( | ||
<div> | ||
{contentData.map(({ name }) => ( | ||
<div key={name}>{name}</div> | ||
))} | ||
</div> | ||
); | ||
}), | ||
})); | ||
|
||
jest.mock('./DonorsLookup', () => ({ | ||
DonorsLookup: jest.fn(({ onAddDonors }) => { | ||
return ( | ||
<div> | ||
<button | ||
type="button" | ||
onClick={() => onAddDonors([mockVendor])} | ||
> | ||
Add donor | ||
</button> | ||
</div> | ||
); | ||
}), | ||
})); | ||
|
||
const setDonorIds = jest.fn(); | ||
|
||
jest.mock('./hooks', () => ({ | ||
useFetchDonors: jest.fn().mockReturnValue({ | ||
donors: [], | ||
isLoading: false, | ||
}), | ||
})); | ||
|
||
const defaultProps = { | ||
columnMapping: {}, | ||
columnWidths: {}, | ||
donors: [], | ||
fields: { | ||
value: [ | ||
'1', | ||
'2', | ||
], | ||
}, | ||
formatter: {}, | ||
id: 'donors', | ||
setDonorIds, | ||
searchLabel: 'Search', | ||
showTriggerButton: true, | ||
visibleColumns: ['name'], | ||
}; | ||
|
||
const renderForm = (props = {}) => ( | ||
<form> | ||
<DonorsContainer | ||
{...defaultProps} | ||
{...props} | ||
/> | ||
<button type="submit">Submit</button> | ||
</form> | ||
); | ||
|
||
const FormCmpt = stripesFinalForm({})(renderForm); | ||
|
||
const renderComponent = (props = {}) => (render( | ||
<MemoryRouter> | ||
<FormCmpt onSubmit={() => { }} {...props} /> | ||
</MemoryRouter>, | ||
)); | ||
|
||
describe('DonorsContainer', () => { | ||
beforeEach(() => { | ||
useFetchDonors.mockClear().mockReturnValue({ | ||
donors: [], | ||
isLoading: false, | ||
}); | ||
}); | ||
|
||
it('should render component', () => { | ||
renderComponent(); | ||
|
||
expect(screen.getByText('Add donor')).toBeDefined(); | ||
}); | ||
|
||
it('should call `useFetchDonors` with `donorOrganizationIds`', () => { | ||
const mockData = [{ name: 'Amazon', code: 'AMAZ', id: '1' }]; | ||
|
||
renderComponent({ donors: mockData }); | ||
expect(screen.getByText(mockData[0].name)).toBeDefined(); | ||
}); | ||
|
||
it('should call `setDonorIds` when `onAddDonors` is called', async () => { | ||
renderComponent({ | ||
donors: [mockVendor], | ||
fields: { | ||
value: [], | ||
push: jest.fn(), | ||
}, | ||
}); | ||
|
||
const addDonorsButton = screen.getByText('Add donor'); | ||
|
||
expect(addDonorsButton).toBeDefined(); | ||
await user.click(addDonorsButton); | ||
expect(setDonorIds).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should not render `DonorsLookup` when `showTriggerButton` is false', () => { | ||
renderComponent({ showTriggerButton: false }); | ||
|
||
expect(screen.queryByText('Add donor')).toBeNull(); | ||
}); | ||
}); |
Oops, something went wrong.