-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #392 from folio-org/yd/checkbox-filter
STCOM-440: Add checkbox filter
- Loading branch information
Showing
5 changed files
with
206 additions
and
0 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
63 changes: 63 additions & 0 deletions
63
lib/SearchAndSort/components/CheckboxFilter/CheckboxFilter.js
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,63 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { Checkbox } from '@folio/stripes-components'; | ||
|
||
export default class CheckboxFilter extends React.Component { | ||
static propTypes = { | ||
dataOptions: PropTypes.arrayOf(PropTypes.shape({ | ||
disabled: PropTypes.bool, | ||
label: PropTypes.node, | ||
readOnly: PropTypes.bool, | ||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | ||
})).isRequired, | ||
name: PropTypes.string.isRequired, | ||
onChange: PropTypes.func.isRequired, | ||
selectedValues: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), | ||
}; | ||
|
||
static defaultProps = { | ||
selectedValues: [], | ||
} | ||
|
||
createOnChangeHandler = (filterValue) => (e) => { | ||
const { | ||
name, | ||
selectedValues, | ||
onChange, | ||
} = this.props; | ||
|
||
const newValues = e.target.checked | ||
? [...selectedValues, filterValue] | ||
: selectedValues.filter((value) => value !== filterValue); | ||
|
||
onChange({ | ||
name, | ||
values: newValues, | ||
}); | ||
}; | ||
|
||
render() { | ||
const { | ||
dataOptions, | ||
selectedValues, | ||
} = this.props; | ||
|
||
return ( | ||
dataOptions.map(({ value, label, disabled, readOnly }) => { | ||
return ( | ||
<Checkbox | ||
{...this.props} | ||
data-test-checkbox-filter-data-option={value} | ||
key={value} | ||
label={label} | ||
disabled={disabled} | ||
readOnly={readOnly} | ||
checked={selectedValues.includes(value)} | ||
onChange={this.createOnChangeHandler(value)} | ||
/> | ||
); | ||
}) | ||
); | ||
} | ||
} |
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 @@ | ||
export { default } from './CheckboxFilter'; |
119 changes: 119 additions & 0 deletions
119
lib/SearchAndSort/components/CheckboxFilter/tests/CheckboxFilter-test.js
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,119 @@ | ||
import React from 'react'; | ||
import { describe, beforeEach, it } from '@bigtest/mocha'; | ||
import { expect } from 'chai'; | ||
import sinon from 'sinon'; | ||
|
||
import { mountWithContext } from '@folio/stripes-components/tests/helpers'; | ||
|
||
import CheckboxFilter from '../CheckboxFilter'; | ||
import CheckboxFilterInteractor from './interactor'; | ||
|
||
|
||
describe('CheckboxFilter', () => { | ||
const checkboxFilter = new CheckboxFilterInteractor(); | ||
const onChangeHandler = sinon.spy(); | ||
|
||
const renderComponent = (props) => { | ||
return mountWithContext( | ||
<CheckboxFilter | ||
name="language" | ||
onChange={onChangeHandler} | ||
dataOptions={[ | ||
{ value: 'en', label: 'English' }, | ||
{ value: 'fr', label: 'French' }, | ||
{ value: 'ge', label: 'German' }, | ||
{ value: 'it', label: 'Italian' }, | ||
]} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
|
||
beforeEach(async () => { | ||
await renderComponent(); | ||
|
||
onChangeHandler.resetHistory(); | ||
}); | ||
|
||
it('should render all filter data options', () => { | ||
expect(checkboxFilter.dataOptionsCount).to.equal(4); | ||
}); | ||
|
||
|
||
describe('after click on readonly data option', () => { | ||
beforeEach(async () => { | ||
await renderComponent({ | ||
dataOptions: [ | ||
{ | ||
value: 'en', | ||
label: 'English', | ||
readOnly: true, | ||
}, | ||
] | ||
}); | ||
await checkboxFilter.dataOptions(0).click(); | ||
}); | ||
|
||
it('should not call onChange callback', () => { | ||
expect(onChangeHandler.called).to.equal(false); | ||
}); | ||
}); | ||
|
||
describe('after click on disabled data option', () => { | ||
beforeEach(async () => { | ||
await renderComponent({ | ||
dataOptions: [ | ||
{ | ||
value: 'en', | ||
label: 'English', | ||
disabled: true, | ||
}, | ||
] | ||
}); | ||
await checkboxFilter.dataOptions(0).click(); | ||
}); | ||
|
||
it('should not call onChange callback', () => { | ||
expect(onChangeHandler.called).to.equal(false); | ||
}); | ||
}); | ||
|
||
describe('when there are selected data options', () => { | ||
beforeEach(async () => { | ||
await renderComponent({ | ||
selectedValues: ['fr', 'ge'], | ||
}); | ||
}); | ||
|
||
it('should render selected data options', () => { | ||
expect(checkboxFilter.dataOptions(1).isSelected).to.equal(true); | ||
expect(checkboxFilter.dataOptions(2).isSelected).to.equal(true); | ||
}); | ||
|
||
describe('after click on unselected data option', () => { | ||
beforeEach(async () => { | ||
await checkboxFilter.dataOptions(0).click(); | ||
}); | ||
|
||
it('should raise filter name and new selected values to onChange callback', () => { | ||
expect(onChangeHandler.args[0]).to.deep.equal([{ | ||
name: 'language', | ||
values: ['fr', 'ge', 'en'], | ||
}]); | ||
}); | ||
}); | ||
|
||
describe('after click on selected option', () => { | ||
beforeEach(async () => { | ||
await checkboxFilter.dataOptions(1).click(); | ||
}); | ||
|
||
it('should raise filter name with the remaining selected values to onChange callback', () => { | ||
expect(onChangeHandler.args[0]).to.deep.equal([{ | ||
name: 'language', | ||
values: ['ge'], | ||
}]); | ||
}); | ||
}); | ||
}); | ||
}); |
19 changes: 19 additions & 0 deletions
19
lib/SearchAndSort/components/CheckboxFilter/tests/interactor.js
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,19 @@ | ||
import { | ||
count, | ||
clickable, | ||
interactor, | ||
collection, | ||
is | ||
} from '@bigtest/interactor'; | ||
|
||
const DataOption = interactor(class DataOptionInteractor { | ||
click = clickable(); | ||
isSelected = is('[checked]'); | ||
isDisabled = is('disabled'); | ||
isReadOnly = is('readonly') | ||
}); | ||
|
||
export default interactor(class CheckboxFilterInteractor { | ||
dataOptionsCount = count('[data-test-checkbox-filter-data-option]'); | ||
dataOptions = collection('[data-test-checkbox-filter-data-option]', DataOption); | ||
}); |