diff --git a/invenio_app_ils/config.py b/invenio_app_ils/config.py index f9bf52162..349008e65 100644 --- a/invenio_app_ils/config.py +++ b/invenio_app_ils/config.py @@ -53,8 +53,9 @@ from .documents.api import DOCUMENT_PID_FETCHER, DOCUMENT_PID_MINTER, \ DOCUMENT_PID_TYPE, Document from .documents.search import DocumentSearch -from .facets import default_value_when_missing_filter, keyed_range_filter, \ - not_empty_object_or_list_filter, overdue_agg, overdue_loans_filter +from .facets import date_range_filter, default_value_when_missing_filter, \ + keyed_range_filter, not_empty_object_or_list_filter, overdue_agg, \ + overdue_loans_filter from .records.views import UserInfoResource from .api import ( # isort:skip @@ -1191,6 +1192,7 @@ def _(x): ), filters={ "returns.end_date": overdue_loans_filter("end_date"), + "loan.start_date": date_range_filter("start_date"), }, post_filters=dict( state=terms_filter("state"), diff --git a/invenio_app_ils/facets.py b/invenio_app_ils/facets.py index d68c62918..a07f0b01a 100644 --- a/invenio_app_ils/facets.py +++ b/invenio_app_ils/facets.py @@ -6,7 +6,6 @@ # it under the terms of the MIT License; see LICENSE file for more details. """Facets and factories for result filtering and aggregation.""" -from datetime import timedelta import arrow from elasticsearch_dsl.query import Bool, Q, Range @@ -113,3 +112,22 @@ def overdue_agg(): ) ) ) + + +# loan.start_date:2020-02-02,2020-12-30 +def date_range_filter(field): + """Create a range filter. + + :param field: Field name. + :param values[0]: string with comma separated fromDate and toDate. + """ + def inner(values): + fromDate, toDate = values[0].split(',') + params = {} + if fromDate: + params["gte"] = str(arrow.get(fromDate).date()) + if toDate: + params["lte"] = str(arrow.get(toDate).date()) + return Range(**{field: params}) + + return inner diff --git a/ui/package-lock.json b/ui/package-lock.json index 023e4a281..c6e5154ae 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -14418,9 +14418,9 @@ } }, "react-searchkit": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/react-searchkit/-/react-searchkit-0.16.0.tgz", - "integrity": "sha512-tFfHdUa1Nih61XHaUr46KF7ksmA3N8oCq8Xc+w/+eJF0apMaHFxERfa8CK3HDcYahNzQPL056KmRfsN6+xkM+g==" + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-searchkit/-/react-searchkit-0.17.0.tgz", + "integrity": "sha512-RKzD32VDvJCHkfRt9PDJR4ghrq2amnPR5z0SMBoWESJB2q+IqsDqo+KPw3svphm5+C/i70X9NKwzdCHcbrX4SA==" }, "react-show-more": { "version": "2.0.0", diff --git a/ui/package.json b/ui/package.json index 521269dfb..2979b2efb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -30,7 +30,7 @@ "react-router-dom": "^5.1.2", "react-scripts": "^3.4.0", "react-scroll": "^1.7.16", - "react-searchkit": "^0.16.0", + "react-searchkit": "^0.17.0", "react-show-more": "^2.0.0", "react-tagcloud": "^2.0.0", "redux": "^4.0.4", diff --git a/ui/src/components/SearchControls/components/SearchDateRange/SearchDateRange.js b/ui/src/components/SearchControls/components/SearchDateRange/SearchDateRange.js new file mode 100644 index 000000000..40066c28d --- /dev/null +++ b/ui/src/components/SearchControls/components/SearchDateRange/SearchDateRange.js @@ -0,0 +1,72 @@ +import React, { Component } from 'react'; +import { Card } from 'semantic-ui-react'; +import { DatePicker } from '@components'; +import { withState, onQueryChanged } from 'react-searchkit'; +import _fromPairs from 'lodash/fromPairs'; +import _toPairs from 'lodash/toPairs'; +import _cloneDeep from 'lodash/cloneDeep'; + +class _SearchDateRange extends Component { + constructor(props) { + super(props); + const [fromDate, toDate] = this.parseUrlDates(); + this.state = { fromDate, toDate }; + } + + parseUrlDates = () => { + const { filters } = this.props.currentQueryState; + const filtersObj = _fromPairs(filters); + const dateFilter = filtersObj['loan.start_date']; + if (dateFilter) return dateFilter.split(','); + return ['', '']; + }; + + updateFilters = () => { + const newQuery = _cloneDeep(this.props.currentQueryState); + const filtersObj = _fromPairs(newQuery.filters); + filtersObj[ + 'loan.start_date' + ] = `${this.state.fromDate},${this.state.toDate}`; + newQuery.filters = _toPairs(filtersObj); + + // NOTE: since its wrapped with `withState` when the pr is merged + // (https://github.com/inveniosoftware/react-searchkit/pull/100) we could + // use this.props.updateStateQuery(newQuery) instead of the events. + onQueryChanged({ searchQuery: newQuery }); + }; + + render() { + return ( + + + Date + + *Loan start date + + + + + this.setState({ fromDate: value }, this.updateFilters) + } + /> + + + + this.setState({ toDate: value }, this.updateFilters) + } + /> + + + ); + } +} + +export const SearchDateRange = withState(_SearchDateRange); diff --git a/ui/src/components/SearchControls/components/SearchDateRange/index.js b/ui/src/components/SearchControls/components/SearchDateRange/index.js new file mode 100644 index 000000000..20d0ef835 --- /dev/null +++ b/ui/src/components/SearchControls/components/SearchDateRange/index.js @@ -0,0 +1 @@ +export { SearchDateRange } from './SearchDateRange'; diff --git a/ui/src/components/SearchControls/components/index.js b/ui/src/components/SearchControls/components/index.js index 6059743d0..d8c85747c 100644 --- a/ui/src/components/SearchControls/components/index.js +++ b/ui/src/components/SearchControls/components/index.js @@ -1,5 +1,6 @@ export { SearchAggregationsCards } from './SearchAggregations'; export { SearchAggregationsMenu } from './SearchAggregations'; +export { SearchDateRange } from './SearchDateRange'; export { SearchFooter } from './SearchFooter'; export { SearchPagination } from './SearchPagination'; export { SearchEmptyResults } from './SearchEmptyResults'; diff --git a/ui/src/pages/backoffice/Loan/LoanSearch/LoanSearch.js b/ui/src/pages/backoffice/Loan/LoanSearch/LoanSearch.js index d13ef651e..17269d665 100644 --- a/ui/src/pages/backoffice/Loan/LoanSearch/LoanSearch.js +++ b/ui/src/pages/backoffice/Loan/LoanSearch/LoanSearch.js @@ -23,6 +23,8 @@ import { SearchAggregationsCards, } from '@components/SearchControls'; +import { SearchDateRange } from '@components/SearchControls/components'; + export class LoanSearch extends Component { searchApi = new InvenioSearchApi({ url: loanApi.searchBaseURL, @@ -77,7 +79,11 @@ export class LoanSearch extends Component { <>
Loans and requests
- + @@ -87,6 +93,7 @@ export class LoanSearch extends Component {
+