@k-int/stripes-kint-components 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _excluded = ["searchKey", "filterKeys", "sortKeys", "stats"];
8
+
9
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
10
+
11
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
12
+
13
+ function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest(); }
14
+
15
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
16
+
17
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
18
+
19
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
20
+
21
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
22
+
23
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
24
+
25
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
26
+
27
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
28
+
29
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
30
+
31
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
32
+
33
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
34
+
35
+ var generateKiwtQueryParams = function generateKiwtQueryParams(options, nsValues) {
36
+ var qindex = nsValues.qindex,
37
+ query = nsValues.query,
38
+ filters = nsValues.filters,
39
+ sort = nsValues.sort;
40
+
41
+ var _options$searchKey = options.searchKey,
42
+ searchKey = _options$searchKey === void 0 ? '' : _options$searchKey,
43
+ _options$filterKeys = options.filterKeys,
44
+ filterKeys = _options$filterKeys === void 0 ? {} : _options$filterKeys,
45
+ _options$sortKeys = options.sortKeys,
46
+ sortKeys = _options$sortKeys === void 0 ? {} : _options$sortKeys,
47
+ _options$stats = options.stats,
48
+ stats = _options$stats === void 0 ? true : _options$stats,
49
+ rest = _objectWithoutProperties(options, _excluded);
50
+
51
+ var paramsArray = [];
52
+
53
+ if (query) {
54
+ var _split;
55
+
56
+ paramsArray.push.apply(paramsArray, _toConsumableArray((_split = (qindex || searchKey).split(',')) === null || _split === void 0 ? void 0 : _split.map(function (m) {
57
+ return "match=".concat(m);
58
+ })));
59
+ paramsArray.push("term=".concat(query));
60
+ }
61
+
62
+ if (filters) {
63
+ var filterMap = {};
64
+ filters.split(',').forEach(function (filter) {
65
+ var _filter$split = filter.split('.'),
66
+ _filter$split2 = _toArray(_filter$split),
67
+ filterName = _filter$split2[0],
68
+ filterRest = _filter$split2.slice(1);
69
+
70
+ var filterValue = filterRest.join('.');
71
+ if (filterMap[filterName] === undefined) filterMap[filterName] = [];
72
+ filterMap[filterName].push(filterValue);
73
+ }); // We now have a filterMap of shape { status: ['active', 'cancelled'], type: ['local'] }
74
+
75
+ Object.entries(filterMap).forEach(function (_ref) {
76
+ var _ref2 = _slicedToArray(_ref, 2),
77
+ filterName = _ref2[0],
78
+ filterValues = _ref2[1];
79
+
80
+ var filterKey = filterKeys[filterName];
81
+
82
+ if (!filterKey) {
83
+ // These filters have no key mapping so we just pass the values to the backend as-is.
84
+ paramsArray.push.apply(paramsArray, _toConsumableArray(filterValues === null || filterValues === void 0 ? void 0 : filterValues.map(function (f) {
85
+ return "filters=".concat(f);
86
+ })));
87
+ } else {
88
+ var filterString = filterValues.map(function (v) {
89
+ return "".concat(filterKey, "==").concat(v);
90
+ }).join('||');
91
+ paramsArray.push("filters=".concat(filterString));
92
+ }
93
+ });
94
+ }
95
+
96
+ if (sort) {
97
+ paramsArray.push.apply(paramsArray, _toConsumableArray(sort.split(',').map(function (sortKey) {
98
+ var descending = sortKey.startsWith('-');
99
+ var term = sortKey.replace('-', '');
100
+
101
+ if (term in sortKeys) {
102
+ term = term.replace(term, sortKeys[term]);
103
+ }
104
+
105
+ return "sort=".concat(term, ";").concat(descending ? 'desc' : 'asc');
106
+ })));
107
+ }
108
+
109
+ if (stats) {
110
+ paramsArray.push('stats=true');
111
+ }
112
+
113
+ for (var _i2 = 0, _Object$entries = Object.entries(rest); _i2 < _Object$entries.length; _i2++) {
114
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2),
115
+ key = _Object$entries$_i[0],
116
+ value = _Object$entries$_i[1];
117
+
118
+ paramsArray.push("".concat(key, "=").concat(value));
119
+ }
120
+
121
+ return paramsArray;
122
+ };
123
+
124
+ var _default = generateKiwtQueryParams;
125
+ exports["default"] = _default;
@@ -15,9 +15,25 @@ Object.defineProperty(exports, "generateKiwtQuery", {
15
15
  return _generateKiwtQuery["default"];
16
16
  }
17
17
  });
18
+ Object.defineProperty(exports, "generateKiwtQueryParams", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _generateKiwtQueryParams["default"];
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "selectorSafe", {
25
+ enumerable: true,
26
+ get: function get() {
27
+ return _selectorSafe["default"];
28
+ }
29
+ });
18
30
 
19
31
  var _generateKiwtQuery = _interopRequireDefault(require("./generateKiwtQuery"));
20
32
 
33
+ var _generateKiwtQueryParams = _interopRequireDefault(require("./generateKiwtQueryParams"));
34
+
35
+ var _selectorSafe = _interopRequireDefault(require("./selectorSafe"));
36
+
21
37
  var _buildUrl = _interopRequireDefault(require("./buildUrl"));
22
38
 
23
39
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k-int/stripes-kint-components",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Stripes Component library for K-Int specific applications",
5
5
  "sideEffects": [
6
6
  "*.css"
package/src/index.js CHANGED
@@ -5,13 +5,16 @@ export {
5
5
  useKiwtSASQuery,
6
6
  useLocalStorageState,
7
7
  useMutateRefdataValue,
8
+ useQIndex,
8
9
  useRefdata,
9
10
  useTemplates,
10
11
  } from './lib/hooks';
11
12
 
12
13
  // Useful utility functions
13
14
  export {
14
- generateKiwtQuery
15
+ generateKiwtQuery,
16
+ generateKiwtQueryParams,
17
+ selectorSafe
15
18
  } from './lib/utils';
16
19
 
17
20
  // Settings Components
@@ -58,3 +61,6 @@ export {
58
61
  export {
59
62
  default as SASQViewComponent
60
63
  } from './lib/SASQViewComponent';
64
+
65
+ // NoResultsMessage
66
+ export { NoResultsMessage } from './lib/NoResultsMessage';
@@ -0,0 +1,78 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { FormattedMessage } from 'react-intl';
4
+ import { Button, Icon } from '@folio/stripes/components';
5
+ import css from '../../../styles/NoResultsMessage.css';
6
+
7
+ const NoResultsMessage = ({
8
+ icon: userIcon,
9
+ isLoading,
10
+ isError,
11
+ error,
12
+ filterPaneIsVisible,
13
+ label: userLabel,
14
+ searchTerm,
15
+ toggleFilterPane,
16
+ }) => {
17
+ let icon = 'search';
18
+ let label = <FormattedMessage id="stripes-smart-components.sas.noResults.default" values={{ searchTerm }} />;
19
+
20
+ // No search term but no results
21
+ if (!searchTerm) {
22
+ icon = 'search';
23
+ label = <FormattedMessage id="stripes-smart-components.sas.noResults.noResults" />;
24
+ }
25
+
26
+ // Loading results
27
+ if (isLoading) {
28
+ icon = 'spinner-ellipsis';
29
+ label = <FormattedMessage id="stripes-smart-components.sas.noResults.loading" />;
30
+ }
31
+
32
+ // Request failure
33
+ if (isError) {
34
+ icon = 'exclamation-circle';
35
+ label = error?.message;
36
+ }
37
+
38
+ return (
39
+ <div className={css.noResultsMessage}>
40
+ <div className={css.noResultsMessageLabelWrap}>
41
+ {(icon || userIcon) &&
42
+ <Icon
43
+ icon={userIcon ?? icon}
44
+ iconRootClass={css.noResultsMessageIcon}
45
+ />
46
+ }
47
+ <span className={css.noResultsMessageLabel}>{userLabel ?? label}</span>
48
+ </div>
49
+ {/* If the filter pane is closed we show a button that toggles filter pane */}
50
+ {!filterPaneIsVisible && (
51
+ <Button
52
+ buttonClass={css.noResultsMessageButton}
53
+ marginBottom0
54
+ onClick={toggleFilterPane}
55
+ >
56
+ <FormattedMessage id="stripes-kint-components.noResultsMessage.showFilters" />
57
+ </Button>
58
+ )}
59
+ </div>
60
+ );
61
+ };
62
+
63
+ NoResultsMessage.propTypes = {
64
+ error: PropTypes.object,
65
+ filterPaneIsVisible: PropTypes.bool.isRequired,
66
+ icon: PropTypes.string,
67
+ isLoading: PropTypes.bool,
68
+ isError: PropTypes.bool,
69
+ label: PropTypes.oneOfType(
70
+ PropTypes.string,
71
+ PropTypes.node,
72
+ PropTypes.func
73
+ ),
74
+ searchTerm: PropTypes.string.isRequired,
75
+ toggleFilterPane: PropTypes.func.isRequired,
76
+ };
77
+
78
+ export default NoResultsMessage;
@@ -0,0 +1 @@
1
+ export { default as NoResultsMessage } from './NoResultsMessage';
@@ -20,12 +20,14 @@ import {
20
20
  MultiColumnList,
21
21
  Pane,
22
22
  PaneMenu,
23
- SearchField
23
+ SearchField,
24
24
  } from '@folio/stripes/components';
25
+ import { NoResultsMessage } from '../NoResultsMessage';
25
26
 
26
27
  import { generateKiwtQuery } from '../utils';
27
28
  import { useKiwtSASQuery, useLocalStorageState } from '../hooks';
28
29
 
30
+
29
31
  const SASQLookupComponent = ({
30
32
  children,
31
33
  fetchParameters = {},
@@ -55,7 +57,15 @@ const SASQLookupComponent = ({
55
57
  };
56
58
 
57
59
  const [filterPaneVisible, setFilterPaneVisible] = useLocalStorageState(filterPaneVisibileKey, true);
58
- const { data: totalData = {}, fetchNextPage } = useInfiniteQuery(
60
+ const toggleFilterPane = () => setFilterPaneVisible(!filterPaneVisible);
61
+
62
+ const {
63
+ data: totalData = {},
64
+ error,
65
+ isError,
66
+ isLoading,
67
+ fetchNextPage,
68
+ } = useInfiniteQuery(
59
69
  [namespace, id, 'data', query],
60
70
  fetchPageData
61
71
  );
@@ -88,13 +98,13 @@ const SASQLookupComponent = ({
88
98
  fetchNextPage({ pageParam: index });
89
99
  };
90
100
 
91
- // Build the map of column definitions
92
- const columnMapping = Object.fromEntries(
93
- resultColumns.map(e => [e.propertyPath, e.label])
94
- );
101
+ // Build the map of column definitions
102
+ const columnMapping = Object.fromEntries(
103
+ resultColumns.map(e => [e.propertyPath, e.label])
104
+ );
95
105
 
96
- // Build the list of visible columns
97
- const visibleColumns = resultColumns.map(e => e.propertyPath);
106
+ // Build the list of visible columns
107
+ const visibleColumns = resultColumns.map(e => e.propertyPath);
98
108
 
99
109
  return (
100
110
  <SearchAndSortQuery
@@ -126,6 +136,18 @@ const SASQLookupComponent = ({
126
136
  autosize
127
137
  columnMapping={columnMapping}
128
138
  contentData={data?.results}
139
+ isEmptyMessage={
140
+ <NoResultsMessage
141
+ {...{
142
+ error,
143
+ isError,
144
+ isLoading,
145
+ filterPaneIsVisible: filterPaneVisible,
146
+ searchTerm: query.query,
147
+ toggleFilterPane
148
+ }}
149
+ />
150
+ }
129
151
  isSelected={({ item }) => item.id === match?.params?.id}
130
152
  onHeaderClick={onSort}
131
153
  onNeedMoreData={onNeedMoreData}
@@ -6,7 +6,7 @@ A component designed to speed up the basic 3-pane layout setup process, SASQRout
6
6
  import React from 'react';
7
7
  import { FormattedMessage } from 'react-intl';
8
8
 
9
- import SASQRoute from '@k-int/stripes-kint-components/src/lib/SASQRoute/SASQRoute';
9
+ import { SASQRoute } from '@k-int/stripes-kint-components';
10
10
  import ActionItem from '../components/ActionItem';
11
11
 
12
12
  const ActionedRoute = ({ path }) => {
@@ -1,115 +1 @@
1
- ```
2
- import React from 'react';
3
-
4
- import { Button, Col, Pane, Row, TextField } from '@folio/stripes/components';
5
- import { AppIcon } from '@folio/stripes/core';
6
- import { generateKiwtQuery, TypeDown } from '@k-int/stripes-kint-components';
7
-
8
- import { Form, Field, useFormState } from 'react-final-form';
9
-
10
- const TestField = () => {
11
- const pathMutator = (input, path) => {
12
- const query = generateKiwtQuery(
13
- {
14
- searchKey: 'name,alternateNames.name',
15
- stats: false
16
- }, {
17
- sort: 'name',
18
- query: input,
19
- }
20
- );
21
-
22
- return `${path}${query}`;
23
- };
24
-
25
- console.log("Current values: %o", useFormState()?.values)
26
- return (
27
- <Field
28
- component={TypeDown}
29
- name="test"
30
- path="erm/sas"
31
- pathMutator={pathMutator}
32
- renderFooter={() => (
33
- <>
34
- <Button
35
- id="footer button 1"
36
- marginBottom0
37
- onClick={() => {
38
- alert('sup')
39
- }}
40
- type="button"
41
- >
42
- Hello 1
43
- </Button>
44
- <Button
45
- id="footer button 2"
46
- marginBottom0
47
- onClick={() => {
48
- alert('sup 2')
49
- }}
50
- type="button"
51
- >
52
- Hello 2
53
- </Button>
54
- </>
55
- )}
56
- renderListItem={agreement => {
57
- return (
58
- <>
59
- <AppIcon
60
- app="agreements"
61
- size="small"
62
- >
63
- {agreement.name}
64
- </AppIcon>
65
- </>
66
- );
67
- }}
68
- />
69
- );
70
- };
71
-
72
-
73
- const TestComponent = () => {
74
- return (
75
- <Pane
76
- defaultWidth="fill"
77
- dismissible
78
- id="test-typedown"
79
- paneTitle={"Test typedown"}
80
- >
81
- <Form
82
- enableReinitialize
83
- navigationCheck
84
- onSubmit={(values) => console.log("submitting: %o", values)}
85
- subscription={{ values: true }}
86
- >
87
- {({ handleSubmit }) => {
88
- return (
89
- <form onSubmit={handleSubmit}>
90
- <Row>
91
- <Col xs={6}>
92
- <TestField />
93
- </Col>
94
- <Col xs={6}>
95
- <Field
96
- component={TextField}
97
- name="test2"
98
- />
99
- </Col>
100
- </Row>
101
- <Button
102
- type="submit"
103
- >
104
- submit
105
- </Button>
106
- </form>
107
- );
108
- }}
109
- </Form>
110
- </Pane>
111
- );
112
- };
113
-
114
- export default TestComponent;
115
- ```
1
+ DEPRECATED - DO NOT USE. You probably want Typedown
@@ -21,6 +21,7 @@ endpoint | string | The endpoint to fetch refdataValues from | | ✓ |
21
21
  desc | string | The refdataCategory (usually of the form `DomainClass.Field`) | | ✕ |
22
22
  queryParams | object | A set of queryParameters to hand to react-query's `useQuery` | | ✕ |
23
23
  returnQueryObject | bool | A switch to return the entirety of the queryObject from useQuery. If `false`, the data will be destructured, if `true` the return will be the full object returned by react-query's `useQuery` | false | ✕ |
24
+ options | object | An object of the shape SASQ_MAP (See generateKiwtQuery) to pass to the generateKiwtQuery inside. Any passed desc "d" will be passed as a filter `DescKey.${d}`, with DescKey acting as FilterName, assuming `filterKeys: { DescKey: "desc" }` in options, so `desc==${d}` is passed directly to the backend. | `{filterKeys: {DescKey: "desc" }, stats: false, max: 100}` | ✕ |
24
25
 
25
26
  ## useMutateRefdataValue
26
27
  A hook for mutations (Create/Delete/Edit) of refdataValues.
@@ -117,6 +118,8 @@ A hook which takes an object containing various helper components to render, and
117
118
  When the url contains a query of the form `helper={name}`, this hook will check the helpers object it was handed for a key matching `{name}`, and if there is one it will return the component value for that key.
118
119
 
119
120
  The hook also returns an object `helperToggleFunctions`, which will have the same keys as were handed to the hook, and values corresponding to "toggle" functions for that key. These functions are a simple way to change the helper query in the url.
121
+
122
+ Finally the hook also returns an ease-of-use function `isOpen`, which takes a string input and returns a boolean if the current helper in the URL matches that string or not.
120
123
  ### Basic usage
121
124
  ```
122
125
  import { useHelperApp } from '@k-int/stripes-kint-components'
@@ -181,3 +184,34 @@ import { useQuery } from 'react-query';
181
184
  </SearchAndSortQuery>
182
185
 
183
186
  ```
187
+
188
+ ## useQIndex
189
+ A hook with a similar API to setState, but instead stores a value in the `qindex` parameter in the URL.
190
+ Returns an array `[qindex, setQindex]`. There is no way to set an initialValue with the hook, as the state is derived from the URL rather than the other way around. This means that multiple `useQIndex` hooks can exist at once.
191
+
192
+ ### BasicUsage
193
+ ```
194
+ import {
195
+ Button,
196
+ } from '@folio/stripes/components';
197
+ import useQindex from '../../../../stripes-kint-components/src/lib/hooks/useQIndex';
198
+
199
+ const Test() {
200
+ const [qindex, setQindex] = useQindex();
201
+
202
+ return (
203
+ <>
204
+ <Button
205
+ onClick={() => setQindex(qindex + "1")}
206
+ >
207
+ change the qindex
208
+ </Button>
209
+ <div>
210
+ {`The current qindex is: ${qindex}`
211
+ </div>
212
+ </>
213
+ );
214
+ }
215
+
216
+ export default Test;
217
+ ```
@@ -5,3 +5,5 @@ export { default as useActiveElement } from './useActiveElement';
5
5
  export { default as useKiwtSASQuery } from './useKiwtSASQuery';
6
6
  export { default as useHelperApp } from './useHelperApp';
7
7
  export { default as useLocalStorageState } from './useLocalStorageState';
8
+ export { default as useQIndex } from './useQIndex';
9
+
@@ -13,6 +13,10 @@ const useHelperApp = (helpers) => {
13
13
  setCurrentHelper(helper !== currentHelper ? helper : undefined);
14
14
  }, [currentHelper]);
15
15
 
16
+ const isOpen = (hlp) => {
17
+ return currentHelper === hlp;
18
+ };
19
+
16
20
  useEffect(() => {
17
21
  if (currentHelper !== query?.helper) {
18
22
  const newQuery = {
@@ -56,7 +60,7 @@ const useHelperApp = (helpers) => {
56
60
  helperToggleFunctions[h] = () => handleToggleHelper(h);
57
61
  });
58
62
 
59
- return { HelperComponent, helperToggleFunctions };
63
+ return { HelperComponent, helperToggleFunctions, isOpen };
60
64
  };
61
65
 
62
66
  export default useHelperApp;
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
2
2
  import { useLocation, useHistory } from 'react-router-dom';
3
3
 
4
4
  import buildUrl from '../utils/buildUrl';
5
+ import useQindex from './useQIndex';
5
6
 
6
7
  const locationQuerySetter = ({ location, history, nsValues }) => {
7
8
  const url = buildUrl(location, nsValues);
@@ -13,8 +14,15 @@ const useKiwtSASQuery = () => {
13
14
  const location = useLocation();
14
15
  const [query, setQuery] = useState({});
15
16
  const queryGetter = () => query;
17
+
18
+ const [qindex] = useQindex();
19
+ // Ensure we update the query along with the querySetter
20
+ if (query.qindex !== qindex) {
21
+ setQuery({ ...query, qindex });
22
+ }
23
+
16
24
  const querySetter = ({ nsValues }) => {
17
- setQuery(nsValues);
25
+ setQuery({ ...query, ...nsValues, qindex });
18
26
  locationQuerySetter({ location, history, nsValues });
19
27
  };
20
28
  return { query, queryGetter, querySetter };
@@ -0,0 +1,41 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useHistory, useLocation } from 'react-router-dom';
3
+ import queryString from 'query-string';
4
+
5
+ const useQIndex = () => {
6
+ const history = useHistory();
7
+ const location = useLocation();
8
+
9
+ const query = queryString.parse(location.search);
10
+ const [currentQindex, setCurrentQindex] = useState(query?.qindex);
11
+
12
+ const handleQindexChange = (newQindex) => {
13
+ setCurrentQindex(newQindex);
14
+ if (newQindex !== query?.qindex) {
15
+ const newQuery = {
16
+ ...query,
17
+ qindex: newQindex
18
+ };
19
+
20
+ history.push({
21
+ pathname: location.pathname,
22
+ search: `?${queryString.stringify(newQuery)}`
23
+ });
24
+ }
25
+ };
26
+
27
+ useEffect(() => {
28
+ if (currentQindex !== query?.qindex) {
29
+ setCurrentQindex(query?.qindex);
30
+ }
31
+ }, [
32
+ currentQindex,
33
+ history,
34
+ location,
35
+ query
36
+ ]);
37
+
38
+ return [currentQindex, handleQindexChange];
39
+ };
40
+
41
+ export default useQIndex;
@@ -4,25 +4,42 @@ import PropTypes from 'prop-types';
4
4
  import { useQuery } from 'react-query';
5
5
  import { useOkapiKy } from '@folio/stripes/core';
6
6
 
7
+ import { generateKiwtQuery } from '../utils';
8
+
7
9
  const useRefdata = ({
8
10
  endpoint,
9
11
  desc,
10
12
  queryParams,
11
- returnQueryObject = false
13
+ returnQueryObject = false,
14
+ options = {
15
+ filterKeys: {
16
+ DescKey: 'desc'
17
+ },
18
+ stats: false,
19
+ max: 100
20
+ }
12
21
  }) => {
13
22
  const ky = useOkapiKy();
14
- let path = endpoint;
23
+
24
+ const nsValues = {};
25
+
26
+ /* Desc will tend to contain a '.', which will throw off generateKiwtQuery.
27
+ * To combat this we can insert another Desc. at the beginning to act as the filtername, so
28
+ * Funder.Name => Desc.desc=Funder.Name. This way "Desc" acts as the filterName, and without a filterKey
29
+ * "desc=Funder.Name" is passed wholesale to the query.
30
+ */
15
31
 
16
32
  if (Array.isArray(desc)) {
17
33
  // If we have an array, append a desc filter for each desc given
18
- desc.forEach((d, index) => {
19
- path += `${index === 0 ? '?filters=' : '%7C%7C'}desc=${d}`;
20
- });
34
+ nsValues.filters = desc.map(d => `DescKey.${d}`).join(',');
21
35
  } else if (desc) {
22
36
  // If we just have a string, append a single desc filter
23
- path += `?filters=desc=${desc}`;
37
+ nsValues.filters = `DescKey.${desc}`;
24
38
  }
25
39
 
40
+ const query = generateKiwtQuery(options, nsValues);
41
+ const path = `${endpoint}${query}`;
42
+
26
43
  const queryObject = useQuery(
27
44
  ['stripes-kint-components', 'useRefdata', 'refdata', desc ?? ''],
28
45
  () => ky(path).json(),