Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERM-3452, Centralise content filter array used in Licenses and Agreem… #716

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as DocumentCard } from './lib/DocumentCard';
export { default as DocumentFilter } from './lib/DocumentFilter';
export { default as DocumentFilterForm } from './lib/DocumentFilter/DocumentFilterForm';
export { default as DocumentFilterFieldArray } from './lib/DocumentFilter/DocumentFilterFieldArray';
export { default as DocumentFilterArray } from './lib/DocumentFilter/DocumentFilterArray';
export { default as DocumentsFieldArray } from './lib/DocumentsFieldArray';
export { default as DuplicateModal } from './lib/DuplicateModal';
export { default as EditCard } from './lib/EditCard';
Expand Down
136 changes: 136 additions & 0 deletions lib/DocumentFilter/DocumentFilterArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import PropTypes from 'prop-types';
import { useState } from 'react';
import { Field, useForm, useFormState } from 'react-final-form';
import { FieldArray } from 'react-final-form-arrays';
import { FormattedMessage, useIntl } from 'react-intl';
import {
Dropdown,
DropdownMenu,
MultiSelection,
Select,
Button,
Label,
IconButton,
Row,
Col,
} from '@folio/stripes/components';

const DocumentFilterArray = ({ translatedContentOptions, handleSubmit, name }) => {
const [open, setOpen] = useState(false);
const { values } = useFormState();
const { change } = useForm();

const intl = useIntl();

return (
<FieldArray name={name}>
{({ fields }) => (
<>
{fields?.map((filter, index) => {
return (
<div key={index}>
{values?.[name][index]?.grouping === '&&' && (
<Label>
<FormattedMessage id="stripes-erm-components.AND" />
</Label>
)}
{values?.[name][index]?.grouping === '||' && (
<Label>
<FormattedMessage id="stripes-erm-components.OR" />
</Label>
)}
<Row xs="end">
<Col xs={10}>
<Field
component={Select}
dataOptions={[
{ value: '', label: '' },
{
value: ' isNotEmpty', // The space is part of the comparator
label: intl.formatMessage({
id: 'stripes-erm-components.documentFilter.has',
}),
},
{
value: ' isEmpty', // The space is part of the comparator
label: intl.formatMessage({
id: 'stripes-erm-components.documentFilter.hasNot',
}),
},
]}
id={`${filter}-attribute-select`}
name={`${filter}.attribute`}
onChange={(e) => {
change(`${filter}.attribute`, e?.target?.value);
handleSubmit();
}}
/>
<Field
key={values[name][index]?.content}
component={MultiSelection}
dataOptions={translatedContentOptions}
id={`${filter}-content-multi-select`}
name={`${filter}.content`}
onChange={(e) => {
change(`${filter}.content`, e);
handleSubmit();
}}
/>
</Col>
{index !== 0 && (
<Col>
<IconButton
icon="times-circle-solid"
onClick={(e) => {
e.stopPropagation();
fields.remove(index);
handleSubmit();
}}
/>
</Col>
)}
</Row>
</div>
);
})}
<Dropdown
label={
<FormattedMessage id="stripes-erm-components.documentFilter.addFilter" />
}
onToggle={() => setOpen(!open)}
open={open}
>
<DropdownMenu>
<Button
buttonStyle="dropdownItem"
onClick={() => {
fields.push({ grouping: '&&' });
setOpen(false);
}}
>
<FormattedMessage id="stripes-erm-components.AND" />
</Button>
<Button
buttonStyle="dropdownItem"
onClick={() => {
fields.push({ grouping: '||' });
setOpen(false);
}}
>
<FormattedMessage id="stripes-erm-components.OR" />
</Button>
</DropdownMenu>
</Dropdown>
</>
)}
</FieldArray>
);
};

DocumentFilterArray.propTypes = {
translatedContentOptions: PropTypes.arrayOf(PropTypes.object),
handleSubmit: PropTypes.func,
name: PropTypes.string,
};

export default DocumentFilterArray;
124 changes: 124 additions & 0 deletions lib/DocumentFilter/DocumentFilterArray.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { MemoryRouter } from 'react-router-dom';
import { waitFor } from '@folio/jest-config-stripes/testing-library/react';
import { renderWithIntl, Button, TestForm, Dropdown } from '@folio/stripes-erm-testing';

import { translationsProperties } from '../../test/jest/helpers';

import DocumentFilterArray from './DocumentFilterArray';

const handleSubmit = jest.fn();
const translatedContentOptions = [
{
'value': 'alternateNames',
'label': 'Alternative names'
},
{
'value': 'agreementContentTypes',
'label': 'Content types'
},
{
'value': 'contacts',
'label': 'Internal contacts'
},
{
'value': 'orgs',
'label': 'Organizations'
},
{
'value': 'items',
'label': 'Agreement lines'
},
{
'value': 'linkedLicenses',
'label': 'Linked licenses'
},
{
'value': 'externalLicenseDocs',
'label': 'External licenses'
},
{
'value': 'supplementaryDocs',
'label': 'Supplementary documents'
},
{
'value': 'usageDataProviders',
'label': 'Usage data'
},
{
'value': 'relatedAgreements',
'label': 'Related agreements'
},
{
'value': 'tags',
'label': 'Tags'
}
];
const onSubmit = jest.fn();
jest.mock('./DocumentFilterField', () => () => <div>DocumentFilterField</div>);

let renderComponent;
describe('DocumentFilterArray', () => {
beforeEach(() => {
renderComponent = renderWithIntl(
<MemoryRouter>
<TestForm onSubmit={onSubmit}>
<DocumentFilterArray
handleSubmit={handleSubmit}
name="agreementContent"
translatedContentOptions={translatedContentOptions}
/>
</TestForm>,
</MemoryRouter>,
translationsProperties
);
});

test('renders the And/Or dropdown button', async () => {
await Dropdown('Add filter').exists();
});

describe('clicking \'Add filter\' button', () => {
beforeEach(async () => {
await waitFor(async () => {
await Button('Add filter').click();
});
});

it('should render the \'AND\' and \'OR\' dropdown buttons', async () => {
await Button('AND').exists();
await Button('OR').exists();
});
});

describe('clicking \'OR\' button', () => {
beforeEach(async () => {
await waitFor(async () => {
await Button('Add filter').click();
await Button('OR').click();
});
});

it('should display the OR label', async () => {
const { getAllByText } = renderComponent;
await waitFor(async () => {
expect(getAllByText('OR').length).toEqual(2);
});
});
});

describe('clicking \'AND\' button', () => {
beforeEach(async () => {
await waitFor(async () => {
await Button('Add filter').click();
await Button('AND').click();
});
});

it('should display the AND label', async () => {
const { getAllByText } = renderComponent;
await waitFor(async () => {
expect(getAllByText('AND').length).toEqual(2);
});
});
});
});
2 changes: 2 additions & 0 deletions translations/stripes-erm-components/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@
"documentFilter.comparator": "Comparator",
"documentFilter.addRule": "Add rule",
"documentFilter.removeRule": "Remove rule {number}",
"documentFilter.has": "Has",
"documentFilter.hasNot": "Has not",
"comparator": "Operator",
"value": "Value",
"contentType": "Content type",
Expand Down
Loading