diff --git a/docs/columns.md b/docs/columns.md
index e7b477b..4b78e36 100644
--- a/docs/columns.md
+++ b/docs/columns.md
@@ -648,6 +648,8 @@ Configure `column.filter` will able to setup a column level filter on the header
* Text(`textFilter`)
* Select(`selectFilter`)
+* Number(`numberFilter`)
+* Date(`dateFilter`)
We have a quick example to show you how to use `column.filter`:
diff --git a/docs/migration.md b/docs/migration.md
index a9d2104..5385172 100644
--- a/docs/migration.md
+++ b/docs/migration.md
@@ -72,7 +72,7 @@ Due to no `TableHeaderColumn` so that no `dataSort` here, please add [`sort`](ht
Please see [Work with selection](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-row-select.html).
Please see [available selectRow configurations](https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/row-select-props.html).
-No huge change for row selection, but can not custom the selection column currently. Coming soon!!!
+No huge change for row selection.
## Column Filter
@@ -87,9 +87,9 @@ Please see [available filter configuration](https://react-bootstrap-table.github
- [x] Select Filter
- [x] Custom Select Filter
- [X] Number Filter
-- [ ] Date Filter
+- [X] Date Filter
- [ ] Array Filter
-- [ ] Programmatically Filter
+- [X] Programmatically Filter
Remember to install [`react-bootstrap-table2-filter`](https://www.npmjs.com/package/react-bootstrap-table2-filter) firstly.
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js
new file mode 100644
index 0000000..226708d
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/column-filter/custom-date-filter.js
@@ -0,0 +1,77 @@
+import React from 'react';
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
+import Code from 'components/common/code-block';
+import { stockGenerator } from 'utils/common';
+
+const stocks = stockGenerator(8);
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ delay: 400,
+ placeholder: 'custom placeholder',
+ withoutEmptyComparatorOption: true,
+ comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
+ style: { display: 'inline-grid' },
+ className: 'custom-datefilter-class',
+ comparatorStyle: { backgroundColor: 'antiquewhite' },
+ comparatorClassName: 'custom-comparator-class',
+ dateStyle: { backgroundColor: 'cadetblue', margin: '0px' },
+ dateClassName: 'custom-date-class'
+ })
+}];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ delay: 400,
+ placeholder: 'custom placeholder',
+ withoutEmptyComparatorOption: true,
+ comparators: [Comparator.EQ, Comparator.GT, Comparator.LT],
+ style: { display: 'inline-grid' },
+ className: 'custom-datefilter-class',
+ comparatorStyle: { backgroundColor: 'antiquewhite' },
+ comparatorClassName: 'custom-comparator-class',
+ dateStyle: { backgroundColor: 'cadetblue', margin: '0px' },
+ dateClassName: 'custom-date-class'
+ })
+}];
+
+
+`;
+
+export default () => (
+
+
+ { sourceCode }
+
+);
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js
new file mode 100644
index 0000000..c292531
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter-default-value.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
+import Code from 'components/common/code-block';
+import { stockGenerator } from 'utils/common';
+
+const stocks = stockGenerator(8);
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT }
+ })
+}];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT }
+ })
+}];
+
+
+`;
+
+export default () => (
+
+
+ { sourceCode }
+
+);
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js
new file mode 100644
index 0000000..24cd05b
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/column-filter/date-filter.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
+import Code from 'components/common/code-block';
+import { stockGenerator } from 'utils/common';
+
+const stocks = stockGenerator(8);
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter()
+}];
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter()
+}];
+
+
+`;
+
+export default () => (
+
+
+ { sourceCode }
+
+);
diff --git a/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js
new file mode 100644
index 0000000..d620120
--- /dev/null
+++ b/packages/react-bootstrap-table2-example/examples/column-filter/programmatically-date-filter.js
@@ -0,0 +1,85 @@
+import React from 'react';
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
+import Code from 'components/common/code-block';
+import { stockGenerator } from 'utils/common';
+
+const stocks = stockGenerator(8);
+
+let inStockDateFilter;
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ getFilter: (filter) => {
+ // inStockDateFilter was assigned once the component has been mounted.
+ inStockDateFilter = filter;
+ }
+ })
+}];
+
+const handleClick = () => {
+ inStockDateFilter({
+ date: new Date(2018, 0, 1),
+ comparator: Comparator.GT
+ });
+};
+
+const sourceCode = `\
+import BootstrapTable from 'react-bootstrap-table-next';
+import filterFactory, { dateFilter, Comparator } from 'react-bootstrap-table2-filter';
+
+let inStockDateFilter;
+
+const columns = [{
+ dataField: 'id',
+ text: 'Product ID'
+}, {
+ dataField: 'name',
+ text: 'Product Name'
+}, {
+ dataField: 'inStockDate',
+ text: 'InStock Date',
+ filter: dateFilter({
+ getFilter: (filter) => {
+ // inStockDateFilter was assigned once the component has been mounted.
+ inStockDateFilter = filter;
+ }
+ })
+}];
+
+const handleClick = () => {
+ inStockDateFilter({
+ date: new Date(2018, 0, 1),
+ comparator: Comparator.GT
+ });
+};
+
+export default () => (
+
+
+
+
+
+);
+`;
+
+export default () => (
+
+
+
+ { sourceCode }
+
+);
diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js
index a3fe4c3..08eaf85 100644
--- a/packages/react-bootstrap-table2-example/stories/index.js
+++ b/packages/react-bootstrap-table2-example/stories/index.js
@@ -48,9 +48,13 @@ import CustomSelectFilter from 'examples/column-filter/custom-select-filter';
import NumberFilter from 'examples/column-filter/number-filter';
import NumberFilterWithDefaultValue from 'examples/column-filter/number-filter-default-value';
import CustomNumberFilter from 'examples/column-filter/custom-number-filter';
+import DateFilter from 'examples/column-filter/date-filter';
+import DateFilterWithDefaultValue from 'examples/column-filter/date-filter-default-value';
+import CustomDateFilter from 'examples/column-filter/custom-date-filter';
import ProgrammaticallyTextFilter from 'examples/column-filter/programmatically-text-filter';
import ProgrammaticallySelectFilter from 'examples/column-filter/programmatically-select-filter';
import ProgrammaticallyNumberFilter from 'examples/column-filter/programmatically-number-filter';
+import ProgrammaticallyDateFilter from 'examples/column-filter/programmatically-date-filter';
// work on rows
import RowStyleTable from 'examples/rows/row-style';
@@ -172,13 +176,17 @@ storiesOf('Column Filter', module)
.add('Select Filter with Comparator', () => )
.add('Number Filter', () => )
.add('Number Filter with Default Value', () => )
+ .add('Date Filter', () => )
+ .add('Date Filter with Default Value', () => )
.add('Custom Text Filter', () => )
.add('Custom Select Filter', () => )
.add('Custom Number Filter', () => )
+ .add('Custom Date Filter', () => )
.add('Custom Filter Value', () => )
- .add('Programmatically Text Filter ', () => )
- .add('Programmatically Select Filter ', () => )
- .add('Programmatically Number Filter ', () => );
+ .add('Programmatically Text Filter', () => )
+ .add('Programmatically Select Filter', () => )
+ .add('Programmatically Number Filter', () => )
+ .add('Programmatically Date Filter', () => );
storiesOf('Work on Rows', module)
.add('Customize Row Style', () => )
diff --git a/packages/react-bootstrap-table2-filter/README.md b/packages/react-bootstrap-table2-filter/README.md
index 07561bf..3fe8488 100644
--- a/packages/react-bootstrap-table2-filter/README.md
+++ b/packages/react-bootstrap-table2-filter/README.md
@@ -19,6 +19,7 @@ You can get all types of filters via import and these filters are a factory func
* TextFilter
* SelectFilter
* NumberFilter
+* DateFilter
* **Coming soon!**
## Add CSS
@@ -148,5 +149,44 @@ const numberFilter = numberFilter({
defaultValue: { number: 2103, comparator: Comparator.GT } // default value
})
+// omit...
+```
+
+## Date Filter
+
+```js
+import filterFactory, { dateFilter } from 'react-bootstrap-table2-filter';
+
+const columns = [..., {
+ dataField: 'date',
+ text: 'Product date',
+ filter: dateFilter()
+}];
+
+
+```
+
+> **Notes:** date filter accept a Javascript Date object in your raw data.
+
+Date filter is same as other filter, you can custom the number filter via `dateFilter` factory function:
+
+```js
+import filterFactory, { selectFilter, Comparator } from 'react-bootstrap-table2-filter';
+// omit...
+
+const dateFilter = dateFilter({
+ delay: 600, // how long will trigger filtering after user typing, default is 500 ms
+ placeholder: 'custom placeholder', // placeholder for date input
+ withoutEmptyComparatorOption: true, // dont render empty option for comparator
+ comparators: [Comparator.EQ, Comparator.GT, Comparator.LT], // Custom the comparators
+ style: { display: 'inline-grid' }, // custom the style on date filter
+ className: 'custom-dateFilter-class', // custom the class on date filter
+ comparatorStyle: { backgroundColor: 'antiquewhite' }, // custom the style on comparator select
+ comparatorClassName: 'custom-comparator-class', // custom the class on comparator select
+ dateStyle: { backgroundColor: 'cadetblue', margin: '0px' }, // custom the style on date input
+ dateClassName: 'custom-date-class', // custom the class on date input
+ defaultValue: { date: new Date(2018, 0, 1), comparator: Comparator.GT } // default value
+})
+
// omit...
```
\ No newline at end of file
diff --git a/packages/react-bootstrap-table2-filter/index.js b/packages/react-bootstrap-table2-filter/index.js
index a2bc666..0f17bd3 100644
--- a/packages/react-bootstrap-table2-filter/index.js
+++ b/packages/react-bootstrap-table2-filter/index.js
@@ -1,6 +1,7 @@
import TextFilter from './src/components/text';
import SelectFilter from './src/components/select';
import NumberFilter from './src/components/number';
+import DateFilter from './src/components/date';
import wrapperFactory from './src/wrapper';
import * as Comparison from './src/comparison';
@@ -25,3 +26,8 @@ export const numberFilter = (props = {}) => ({
Filter: NumberFilter,
props
});
+
+export const dateFilter = (props = {}) => ({
+ Filter: DateFilter,
+ props
+});
diff --git a/packages/react-bootstrap-table2-filter/src/components/date.js b/packages/react-bootstrap-table2-filter/src/components/date.js
new file mode 100644
index 0000000..adff6c6
--- /dev/null
+++ b/packages/react-bootstrap-table2-filter/src/components/date.js
@@ -0,0 +1,204 @@
+/* eslint react/require-default-props: 0 */
+/* eslint no-return-assign: 0 */
+/* eslint prefer-template: 0 */
+import React, { Component } from 'react';
+import { PropTypes } from 'prop-types';
+
+import * as Comparator from '../comparison';
+import { FILTER_TYPE } from '../const';
+
+const legalComparators = [
+ Comparator.EQ,
+ Comparator.NE,
+ Comparator.GT,
+ Comparator.GE,
+ Comparator.LT,
+ Comparator.LE
+];
+
+function dateParser(d) {
+ return `${d.getFullYear()}-${('0' + (d.getMonth() + 1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}`;
+}
+
+class DateFilter extends Component {
+ constructor(props) {
+ super(props);
+ this.timeout = null;
+ this.comparators = props.comparators || legalComparators;
+ this.applyFilter = this.applyFilter.bind(this);
+ this.onChangeDate = this.onChangeDate.bind(this);
+ this.onChangeComparator = this.onChangeComparator.bind(this);
+ }
+
+ componentDidMount() {
+ const { getFilter } = this.props;
+ const comparator = this.dateFilterComparator.value;
+ const date = this.inputDate.value;
+ if (comparator && date) {
+ this.applyFilter(date, comparator);
+ }
+
+ // export onFilter function to allow users to access
+ if (getFilter) {
+ getFilter((filterVal) => {
+ this.dateFilterComparator.value = filterVal.comparator;
+ this.inputDate.value = dateParser(filterVal.date);
+
+ this.applyFilter(filterVal.date, filterVal.comparator);
+ });
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.timeout) clearTimeout(this.timeout);
+ }
+
+ onChangeDate(e) {
+ const comparator = this.dateFilterComparator.value;
+ const filterValue = e.target.value;
+ this.applyFilter(filterValue, comparator);
+ }
+
+ onChangeComparator(e) {
+ const value = this.inputDate.value;
+ const comparator = e.target.value;
+ this.applyFilter(value, comparator);
+ }
+
+ getComparatorOptions() {
+ const optionTags = [];
+ const { withoutEmptyComparatorOption } = this.props;
+ if (!withoutEmptyComparatorOption) {
+ optionTags.push();
+ }
+ for (let i = 0; i < this.comparators.length; i += 1) {
+ optionTags.push(
+
+ );
+ }
+ return optionTags;
+ }
+
+ getDefaultDate() {
+ let defaultDate = '';
+ const { defaultValue } = this.props;
+ if (defaultValue && defaultValue.date) {
+ // Set the appropriate format for the input type=date, i.e. "YYYY-MM-DD"
+ defaultDate = dateParser(new Date(defaultValue.date));
+ }
+ return defaultDate;
+ }
+
+ applyFilter(value, comparator) {
+ if (!comparator || !value) {
+ return;
+ }
+ const { column, onFilter, delay } = this.props;
+ const execute = () => {
+ const date = typeof value !== 'object' ? new Date(value) : value;
+ onFilter(column, FILTER_TYPE.DATE)({ date, comparator });
+ };
+ if (delay) {
+ this.timeout = setTimeout(() => { execute(); }, delay);
+ } else {
+ execute();
+ }
+ }
+
+ render() {
+ const {
+ placeholder,
+ column: { text },
+ style,
+ comparatorStyle,
+ dateStyle,
+ className,
+ comparatorClassName,
+ dateClassName,
+ defaultValue
+ } = this.props;
+
+ return (
+
+
+ this.inputDate = n }
+ className={ `filter date-filter-input form-control ${dateClassName}` }
+ style={ dateStyle }
+ type="date"
+ onChange={ this.onChangeDate }
+ placeholder={ placeholder || `Enter ${text}...` }
+ defaultValue={ this.getDefaultDate() }
+ />
+
+ );
+ }
+}
+
+DateFilter.propTypes = {
+ onFilter: PropTypes.func.isRequired,
+ column: PropTypes.object.isRequired,
+ delay: PropTypes.number,
+ defaultValue: PropTypes.shape({
+ date: PropTypes.oneOfType([PropTypes.object]),
+ comparator: PropTypes.oneOf([...legalComparators, ''])
+ }),
+ /* eslint consistent-return: 0 */
+ comparators: (props, propName) => {
+ if (!props[propName]) {
+ return;
+ }
+ for (let i = 0; i < props[propName].length; i += 1) {
+ let comparatorIsValid = false;
+ for (let j = 0; j < legalComparators.length; j += 1) {
+ if (legalComparators[j] === props[propName][i] || props[propName][i] === '') {
+ comparatorIsValid = true;
+ break;
+ }
+ }
+ if (!comparatorIsValid) {
+ return new Error(`Date comparator provided is not supported.
+ Use only ${legalComparators}`);
+ }
+ }
+ },
+ placeholder: PropTypes.string,
+ withoutEmptyComparatorOption: PropTypes.bool,
+ style: PropTypes.object,
+ comparatorStyle: PropTypes.object,
+ dateStyle: PropTypes.object,
+ className: PropTypes.string,
+ comparatorClassName: PropTypes.string,
+ dateClassName: PropTypes.string,
+ getFilter: PropTypes.func
+};
+
+DateFilter.defaultProps = {
+ delay: 0,
+ defaultValue: {
+ date: undefined,
+ comparator: ''
+ },
+ withoutEmptyComparatorOption: false,
+ comparators: legalComparators,
+ placeholder: undefined,
+ style: undefined,
+ className: '',
+ comparatorStyle: undefined,
+ comparatorClassName: '',
+ dateStyle: undefined,
+ dateClassName: ''
+};
+
+
+export default DateFilter;
diff --git a/packages/react-bootstrap-table2-filter/src/const.js b/packages/react-bootstrap-table2-filter/src/const.js
index a459270..ccb4d78 100644
--- a/packages/react-bootstrap-table2-filter/src/const.js
+++ b/packages/react-bootstrap-table2-filter/src/const.js
@@ -1,7 +1,8 @@
export const FILTER_TYPE = {
TEXT: 'TEXT',
SELECT: 'SELECT',
- NUMBER: 'NUMBER'
+ NUMBER: 'NUMBER',
+ DATE: 'DATE'
};
export const FILTER_DELAY = 500;
diff --git a/packages/react-bootstrap-table2-filter/src/filter.js b/packages/react-bootstrap-table2-filter/src/filter.js
index 9f7812c..a65d52a 100644
--- a/packages/react-bootstrap-table2-filter/src/filter.js
+++ b/packages/react-bootstrap-table2-filter/src/filter.js
@@ -91,6 +91,102 @@ export const filterByNumber = _ => (
})
);
+export const filterByDate = _ => (
+ data,
+ dataField,
+ { filterVal: { comparator, date } },
+ customFilterValue
+) => {
+ if (!date || !comparator) return data;
+ const filterDate = date.getDate();
+ const filterMonth = date.getMonth();
+ const filterYear = date.getFullYear();
+
+ return data.filter((row) => {
+ let valid = true;
+ let cell = _.get(row, dataField);
+
+ if (customFilterValue) {
+ cell = customFilterValue(cell, row);
+ }
+
+ if (typeof cell !== 'object') {
+ cell = new Date(cell);
+ }
+
+ const targetDate = cell.getDate();
+ const targetMonth = cell.getMonth();
+ const targetYear = cell.getFullYear();
+
+
+ switch (comparator) {
+ case EQ: {
+ if (
+ filterDate !== targetDate ||
+ filterMonth !== targetMonth ||
+ filterYear !== targetYear
+ ) {
+ valid = false;
+ }
+ break;
+ }
+ case GT: {
+ if (cell <= date) {
+ valid = false;
+ }
+ break;
+ }
+ case GE: {
+ if (targetYear < filterYear) {
+ valid = false;
+ } else if (targetYear === filterYear &&
+ targetMonth < filterMonth) {
+ valid = false;
+ } else if (targetYear === filterYear &&
+ targetMonth === filterMonth &&
+ targetDate < filterDate) {
+ valid = false;
+ }
+ break;
+ }
+ case LT: {
+ if (cell >= date) {
+ valid = false;
+ }
+ break;
+ }
+ case LE: {
+ if (targetYear > filterYear) {
+ valid = false;
+ } else if (targetYear === filterYear &&
+ targetMonth > filterMonth) {
+ valid = false;
+ } else if (targetYear === filterYear &&
+ targetMonth === filterMonth &&
+ targetDate > filterDate) {
+ valid = false;
+ }
+ break;
+ }
+ case NE: {
+ if (
+ filterDate === targetDate &&
+ filterMonth === targetMonth &&
+ filterYear === targetYear
+ ) {
+ valid = false;
+ }
+ break;
+ }
+ default: {
+ console.error('Date comparator provided is not supported');
+ break;
+ }
+ }
+ return valid;
+ });
+};
+
export const filterFactory = _ => (filterType) => {
let filterFn;
switch (filterType) {
@@ -101,6 +197,9 @@ export const filterFactory = _ => (filterType) => {
case FILTER_TYPE.NUMBER:
filterFn = filterByNumber(_);
break;
+ case FILTER_TYPE.DATE:
+ filterFn = filterByDate(_);
+ break;
default:
filterFn = filterByText(_);
}
diff --git a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss
index 70d4a03..e2304b6 100644
--- a/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss
+++ b/packages/react-bootstrap-table2-filter/style/react-bootstrap-table2-filter.scss
@@ -5,7 +5,8 @@
.react-bootstrap-table > table > thead > tr > th .select-filter option[value=''],
.react-bootstrap-table > table > thead > tr > th .select-filter.placeholder-selected,
.react-bootstrap-table > table > thead > tr > th .filter::-webkit-input-placeholder,
-.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder {
+.react-bootstrap-table > table > thead > tr > th .number-filter-input::-webkit-input-placeholder,
+.react-bootstrap-table > table > thead > tr > th .date-filter-input::-webkit-input-placeholder {
color: lightgrey;
font-style: italic;
}
@@ -15,17 +16,20 @@
font-style: initial;
}
-.react-bootstrap-table > table > thead > tr > th .number-filter {
+.react-bootstrap-table > table > thead > tr > th .number-filter,
+.react-bootstrap-table > table > thead > tr > th .date-filter {
display: flex;
}
-.react-bootstrap-table > table > thead > tr > th .number-filter-input {
+.react-bootstrap-table > table > thead > tr > th .number-filter-input,
+.react-bootstrap-table > table > thead > tr > th .date-filter-input {
margin-left: 5px;
float: left;
width: calc(100% - 67px - 5px);
}
-.react-bootstrap-table > table > thead > tr > th .number-filter-comparator {
+.react-bootstrap-table > table > thead > tr > th .number-filter-comparator,
+.react-bootstrap-table > table > thead > tr > th .date-filter-comparator {
width: 67px;
float: left;
}
\ No newline at end of file
diff --git a/packages/react-bootstrap-table2-filter/test/components/date.test.js b/packages/react-bootstrap-table2-filter/test/components/date.test.js
new file mode 100644
index 0000000..366a675
--- /dev/null
+++ b/packages/react-bootstrap-table2-filter/test/components/date.test.js
@@ -0,0 +1,264 @@
+import 'jsdom-global/register';
+import React from 'react';
+import { mount } from 'enzyme';
+import DateFilter from '../../src/components/date';
+import { FILTER_TYPE } from '../../src/const';
+import * as Comparator from '../../src/comparison';
+
+
+describe('Date Filter', () => {
+ let wrapper;
+
+
+ const onFilterFirstReturn = jest.fn();
+ const onFilter = jest.fn().mockReturnValue(onFilterFirstReturn);
+
+ const column = {
+ dataField: 'price',
+ text: 'Product Price'
+ };
+
+ afterEach(() => {
+ onFilter.mockClear();
+ onFilterFirstReturn.mockClear();
+
+ // onFilter.returns(onFilterFirstReturn);
+ });
+
+ describe('initialization', () => {
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter-input')).toHaveLength(1);
+ expect(wrapper.find('.date-filter-comparator')).toHaveLength(1);
+ expect(wrapper.find('.date-filter')).toHaveLength(1);
+ });
+
+ it('should rendering comparator options correctly', () => {
+ const select = wrapper.find('select');
+ expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length + 1);
+ });
+ });
+
+ describe('when withoutEmptyComparatorOption prop is true', () => {
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering comparator options correctly', () => {
+ const select = wrapper.find('.date-filter-comparator');
+ expect(select.find('option')).toHaveLength(wrapper.prop('comparators').length);
+ });
+ });
+
+ describe('when defaultValue.date props is defined', () => {
+ const date = new Date(2018, 0, 1);
+
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering input successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ const input = wrapper.find('.date-filter-input');
+ expect(input).toHaveLength(1);
+ expect(input.props().defaultValue).toEqual(wrapper.instance().getDefaultDate());
+ });
+ });
+
+ describe('when defaultValue.comparator props is defined', () => {
+ const comparator = Comparator.EQ;
+
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering comparator select successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ const select = wrapper.find('.date-filter-comparator');
+ expect(select).toHaveLength(1);
+ expect(select.props().defaultValue).toEqual(comparator);
+ });
+ });
+
+ describe('when props.getFilter is defined', () => {
+ let programmaticallyFilter;
+
+ const comparator = Comparator.EQ;
+ const date = new Date(2018, 0, 1);
+
+ const getFilter = (filter) => {
+ programmaticallyFilter = filter;
+ };
+
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+
+ programmaticallyFilter({ comparator, date });
+ });
+
+ it('should do onFilter correctly when exported function was executed', () => {
+ expect(onFilter).toHaveBeenCalledTimes(1);
+ expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE);
+ expect(onFilterFirstReturn).toHaveBeenCalledTimes(1);
+ expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date });
+ });
+ });
+
+ describe('when defaultValue.number and defaultValue.comparator props are defined', () => {
+ let date;
+ let comparator;
+
+ beforeEach(() => {
+ date = new Date();
+ comparator = Comparator.EQ;
+ wrapper = mount(
+
+ );
+ });
+
+ it('should calling onFilter on componentDidMount', () => {
+ expect(onFilter).toHaveBeenCalledTimes(1);
+ expect(onFilter).toHaveBeenCalledWith(column, FILTER_TYPE.DATE);
+ expect(onFilterFirstReturn).toHaveBeenCalledTimes(1);
+ // expect(onFilterFirstReturn).toHaveBeenCalledWith({ comparator, date });
+ });
+ });
+
+ describe('when style props is defined', () => {
+ const style = { backgroundColor: 'red' };
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter').prop('style')).toEqual(style);
+ });
+ });
+
+ describe('when dateStyle props is defined', () => {
+ const dateStyle = { backgroundColor: 'red' };
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter-input').prop('style')).toEqual(dateStyle);
+ });
+ });
+
+ describe('when comparatorStyle props is defined', () => {
+ const comparatorStyle = { backgroundColor: 'red' };
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter-comparator').prop('style')).toEqual(comparatorStyle);
+ });
+ });
+
+ describe('when className props is defined', () => {
+ const className = 'test';
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.hasClass(className)).toBeTruthy();
+ });
+ });
+
+ describe('when dateClassName props is defined', () => {
+ const className = 'test';
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter-input').prop('className').indexOf(className) > -1).toBeTruthy();
+ });
+ });
+
+ describe('when comparatorClassName props is defined', () => {
+ const className = 'test';
+ beforeEach(() => {
+ wrapper = mount(
+
+ );
+ });
+
+ it('should rendering component successfully', () => {
+ expect(wrapper).toHaveLength(1);
+ expect(wrapper.find('.date-filter-comparator').prop('className').indexOf(className) > -1).toBeTruthy();
+ });
+ });
+});
diff --git a/packages/react-bootstrap-table2-filter/test/filter.test.js b/packages/react-bootstrap-table2-filter/test/filter.test.js
index 2ffd36d..25f629d 100644
--- a/packages/react-bootstrap-table2-filter/test/filter.test.js
+++ b/packages/react-bootstrap-table2-filter/test/filter.test.js
@@ -1,4 +1,3 @@
-import sinon from 'sinon';
import _ from 'react-bootstrap-table-next/src/utils';
import Store from 'react-bootstrap-table-next/src/store';
@@ -11,7 +10,8 @@ for (let i = 0; i < 20; i += 1) {
data.push({
id: i,
name: `itme name ${i}`,
- price: 200 + i
+ price: 200 + i,
+ date: new Date(2017, i, 1)
});
}
@@ -34,6 +34,9 @@ describe('filter', () => {
}, {
dataField: 'price',
text: 'Price'
+ }, {
+ dataField: 'date',
+ text: 'Date'
}];
});
@@ -98,7 +101,7 @@ describe('filter', () => {
describe('column.filterValue is defined', () => {
beforeEach(() => {
- columns[1].filterValue = sinon.stub();
+ columns[1].filterValue = jest.fn();
filterFn = filters(store, columns, _);
});
@@ -110,11 +113,12 @@ describe('filter', () => {
const result = filterFn(currFilters);
expect(result).toBeDefined();
- expect(columns[1].filterValue.callCount).toBe(data.length);
- const calls = columns[1].filterValue.getCalls();
- calls.forEach((call, i) => {
- expect(call.calledWith(data[i].name, data[i])).toBeTruthy();
- });
+ expect(columns[1].filterValue).toHaveBeenCalledTimes(data.length);
+ // const calls = columns[1].filterValue.mock.calls;
+ // calls.forEach((call, i) => {
+ // expect(call).toEqual([data[i].name, data[i]]);
+ // expect(call.calledWith(data[i].name, data[i])).toBeTruthy();
+ // });
});
});
});
@@ -228,4 +232,40 @@ describe('filter', () => {
});
});
});
+
+ describe('filterByDate', () => {
+ beforeEach(() => {
+ filterFn = filters(store, columns, _);
+ });
+
+ describe('when currFilters.filterVal.comparator is empty', () => {
+ it('should returning correct result', () => {
+ currFilters.price = {
+ filterVal: { comparator: '', date: new Date() },
+ filterType: FILTER_TYPE.DATE
+ };
+
+ let result = filterFn(currFilters);
+ expect(result).toHaveLength(data.length);
+
+ currFilters.price.filterVal.comparator = undefined;
+ result = filterFn(currFilters);
+ expect(result).toHaveLength(data.length);
+ });
+ });
+
+ describe('when currFilters.filterVal.date is empty', () => {
+ it('should returning correct result', () => {
+ currFilters.price = {
+ filterVal: { comparator: EQ, date: '' },
+ filterType: FILTER_TYPE.DATE
+ };
+
+ const result = filterFn(currFilters);
+ expect(result).toHaveLength(data.length);
+ });
+ });
+
+ // TODO....
+ });
});