@k-int/stripes-kint-components 5.21.0 → 5.23.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.
- package/CHANGELOG.md +14 -0
- package/es/lib/NoResultsMessage/NoResultsMessage.js +1 -1
- package/es/lib/SASQLookupComponent/SASQLookupComponent.js +2 -0
- package/es/lib/SASQLookupComponent/TableBody/TableBody.js +5 -2
- package/es/lib/SearchKeyControl/SearchKeyControl.js +45 -21
- package/package.json +1 -1
- package/src/lib/FormattedKintMessage/README.md +80 -0
- package/src/lib/NoResultsMessage/NoResultsMessage.js +1 -1
- package/src/lib/NoResultsMessage/README.md +81 -0
- package/src/lib/SASQLookupComponent/README.md +24 -23
- package/src/lib/SASQLookupComponent/SASQLookupComponent.js +2 -0
- package/src/lib/SASQLookupComponent/TableBody/README.md +19 -18
- package/src/lib/SASQLookupComponent/TableBody/TableBody.js +6 -3
- package/src/lib/SearchKeyControl/README.md +55 -30
- package/src/lib/SearchKeyControl/SearchKeyControl.js +34 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [5.23.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.22.0...v5.23.0) (2025-06-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* SearchKeyControl subIndexes ([40036a4](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/40036a4353f24e47480e8060d901ef44c5c3b6ed))
|
|
7
|
+
|
|
8
|
+
# [5.22.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.21.0...v5.22.0) (2025-06-13)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Customisable NoResultsMessage ([f4b18d8](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/commit/f4b18d809ba83e7d7f6141b2ace09f3e32e18b02))
|
|
14
|
+
|
|
1
15
|
# [5.21.0](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/compare/v5.20.1...v5.21.0) (2025-06-06)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -66,7 +66,7 @@ const NoResultsMessage = _ref => {
|
|
|
66
66
|
iconRootClass: _NoResultsMessage.default.noResultsMessageIcon
|
|
67
67
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
68
68
|
className: _NoResultsMessage.default.noResultsMessageLabel,
|
|
69
|
-
children: userLabel ?? label
|
|
69
|
+
children: userLabel ?? labelOverrides.noResultsLabel ?? label
|
|
70
70
|
})]
|
|
71
71
|
}), !filterPaneIsVisible && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, {
|
|
72
72
|
buttonClass: _NoResultsMessage.default.noResultsMessageButton,
|
|
@@ -46,6 +46,7 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
46
46
|
},
|
|
47
47
|
mainPaneProps = {},
|
|
48
48
|
mclProps = {},
|
|
49
|
+
noResultsProps = {},
|
|
49
50
|
noSearchField,
|
|
50
51
|
persistedPanesetProps = {},
|
|
51
52
|
queryParameterGenerator = _utils.generateKiwtQuery,
|
|
@@ -260,6 +261,7 @@ const SASQLookupComponent = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
260
261
|
intlKey: passedIntlKey,
|
|
261
262
|
intlNS: passedIntlNS,
|
|
262
263
|
labelOverrides: labelOverrides,
|
|
264
|
+
noResultsProps: noResultsProps,
|
|
263
265
|
query: query,
|
|
264
266
|
rowNavigation: rowNavigation,
|
|
265
267
|
toggleFilterPane: toggleFilterPane,
|
|
@@ -27,6 +27,7 @@ const TableBody = _ref => {
|
|
|
27
27
|
formatter = {},
|
|
28
28
|
...mclProps
|
|
29
29
|
} = {},
|
|
30
|
+
noResultsProps = {},
|
|
30
31
|
onSort,
|
|
31
32
|
path,
|
|
32
33
|
resultColumns,
|
|
@@ -82,6 +83,7 @@ const TableBody = _ref => {
|
|
|
82
83
|
} = _ref2;
|
|
83
84
|
return item.id === match?.params?.id;
|
|
84
85
|
}, [match?.params?.id]);
|
|
86
|
+
const NoResultsComponent = (0, _react.useMemo)(() => noResultsProps?.component ?? _NoResultsMessage.default, [noResultsProps?.component]);
|
|
85
87
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.MultiColumnList, {
|
|
86
88
|
autosize: true,
|
|
87
89
|
columnMapping: columnMapping,
|
|
@@ -90,7 +92,7 @@ const TableBody = _ref => {
|
|
|
90
92
|
,
|
|
91
93
|
hasMargin: true,
|
|
92
94
|
interactive: rowNavigation,
|
|
93
|
-
isEmptyMessage: /*#__PURE__*/(0, _jsxRuntime.jsx)(
|
|
95
|
+
isEmptyMessage: /*#__PURE__*/(0, _jsxRuntime.jsx)(NoResultsComponent, {
|
|
94
96
|
error,
|
|
95
97
|
filterPaneIsVisible: filterPaneVisible,
|
|
96
98
|
intlKey: passedIntlKey,
|
|
@@ -99,7 +101,8 @@ const TableBody = _ref => {
|
|
|
99
101
|
isLoading,
|
|
100
102
|
labelOverrides,
|
|
101
103
|
searchTerm: query.query,
|
|
102
|
-
toggleFilterPane
|
|
104
|
+
toggleFilterPane,
|
|
105
|
+
...noResultsProps // Anything passed in directly takes precedence
|
|
103
106
|
}),
|
|
104
107
|
isSelected: isSelected,
|
|
105
108
|
onHeaderClick: onSort,
|
|
@@ -25,9 +25,12 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
25
25
|
|
|
26
26
|
// Memoise this process so keyState changes if and only if options/qIndex change
|
|
27
27
|
const createKeyState = (0, _react.useCallback)(() => options.reduce((acc, curr) => {
|
|
28
|
+
// Is in use if URL contains ALL of the indexes
|
|
29
|
+
const subindexes = (curr?.indexes?.length ?? 0) > 0 ? curr.indexes : [curr.key];
|
|
28
30
|
acc[curr.key] = {
|
|
29
|
-
inUse: qIndexArray
|
|
30
|
-
label: curr.label ?? curr.key
|
|
31
|
+
inUse: subindexes.every(si => qIndexArray.includes(si)),
|
|
32
|
+
label: curr.label ?? curr.key,
|
|
33
|
+
subIndexes: curr.indexes
|
|
31
34
|
};
|
|
32
35
|
return acc;
|
|
33
36
|
}, {}), [options, qIndexArray]);
|
|
@@ -48,11 +51,44 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
48
51
|
} = (0, _hooks.usePrevNextPagination)({
|
|
49
52
|
defaultToPageOne: false
|
|
50
53
|
});
|
|
54
|
+
const handleSearchKeyChange = (0, _react.useCallback)(_ref2 => {
|
|
55
|
+
let {
|
|
56
|
+
e: {
|
|
57
|
+
target: {
|
|
58
|
+
checked: targetIsChecked
|
|
59
|
+
} = {}
|
|
60
|
+
} = {},
|
|
61
|
+
key,
|
|
62
|
+
value
|
|
63
|
+
} = _ref2;
|
|
64
|
+
// Set up which indexes need to change
|
|
65
|
+
const indicesToChange = (value?.subIndexes?.length ?? 0) > 0 ? value.subIndexes : [key];
|
|
66
|
+
|
|
67
|
+
// If false, we must remove from the qIndex
|
|
68
|
+
if (!targetIsChecked) {
|
|
69
|
+
indicesToChange.forEach(ind => {
|
|
70
|
+
const indexOfKey = qIndexArray.indexOf(ind);
|
|
71
|
+
if (indexOfKey > -1) {
|
|
72
|
+
// only splice array when item is found
|
|
73
|
+
qIndexArray.splice(indexOfKey, 1); // 2nd parameter means remove one item only
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} else {
|
|
77
|
+
// If true, we need to add to qIndex
|
|
78
|
+
indicesToChange.forEach(ind => {
|
|
79
|
+
qIndexArray.push(ind);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
setQIndex(qIndexArray?.join(','));
|
|
83
|
+
if (currentPage) {
|
|
84
|
+
resetPage();
|
|
85
|
+
}
|
|
86
|
+
}, [currentPage, qIndexArray, resetPage, setQIndex]);
|
|
51
87
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
52
88
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
53
89
|
className: _SearchKeyControl.default.searchKeyControlContainer,
|
|
54
|
-
children: Object.entries(keyState).map(
|
|
55
|
-
let [key, value] =
|
|
90
|
+
children: Object.entries(keyState).map(_ref3 => {
|
|
91
|
+
let [key, value] = _ref3;
|
|
56
92
|
/* At this point we have "key" corresponding to a searchKey option,
|
|
57
93
|
* and "value" an object of the shape
|
|
58
94
|
{
|
|
@@ -64,23 +100,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
64
100
|
checked: value?.inUse,
|
|
65
101
|
className: _SearchKeyControl.default.searchKeyControlElement,
|
|
66
102
|
label: value?.label,
|
|
67
|
-
onChange: e => {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// only splice array when item is found
|
|
73
|
-
qIndexArray.splice(indexOfKey, 1); // 2nd parameter means remove one item only
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
// If true, we need to add to qIndex
|
|
77
|
-
qIndexArray.push(key);
|
|
78
|
-
}
|
|
79
|
-
setQIndex(qIndexArray?.join(','));
|
|
80
|
-
if (currentPage) {
|
|
81
|
-
resetPage();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
103
|
+
onChange: e => handleSearchKeyChange({
|
|
104
|
+
e,
|
|
105
|
+
key,
|
|
106
|
+
value
|
|
107
|
+
})
|
|
84
108
|
}, `search-key-control-${key}`);
|
|
85
109
|
})
|
|
86
110
|
})
|
package/package.json
CHANGED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# FormattedKintMessage
|
|
2
|
+
|
|
3
|
+
A wrapper component around `react-intl`'s `FormattedMessage` that enhances internationalization capabilities by providing automatic key resolution, direct value overrides, and flexible fallback messaging. **FormattedKintMessage** is designed to work within the `k-int` internationalization ecosystem, leveraging `useIntlKey` for intelligent message key lookup via `useIntlKey` and other intl hooks. [See intl hooks for details](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/-/tree/main/src/lib/hooks/intlHooks)
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
Below is an example demonstrating the most basic use of **FormattedKintMessage** to display translated text using automatic key resolution.
|
|
8
|
+
|
|
9
|
+
```jsx
|
|
10
|
+
import { FormattedKintMessage } from '@k-int/stripes-kint-components';
|
|
11
|
+
|
|
12
|
+
const MyInternationalizedComponent = () => (
|
|
13
|
+
<div>
|
|
14
|
+
{/* Resolves key using intlKey/intlNS from context or props */}
|
|
15
|
+
<FormattedKintMessage id="title.greeting" intlKey="myModule" intlNS="myApp" />
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export default MyInternationalizedComponent;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Explanation
|
|
23
|
+
|
|
24
|
+
* **`id`**: The relative ID for your message, which will be prefixed by the resolved `intlKey`.
|
|
25
|
+
|
|
26
|
+
* **`intlKey` / `intlNS`**: These props are used by `useIntlKey` to determine the base prefix for your message ID, allowing for flexible internationalization key management.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Override and Fallback Message Usage
|
|
31
|
+
|
|
32
|
+
**`overrideValue`** and **`fallbackMessage`** both provide ways to control the message displayed, but they serve distinct purposes:
|
|
33
|
+
|
|
34
|
+
* **`overrideValue`**: Use this when you want to **explicitly define** the content to be displayed, entirely bypassing the translation lookup process for the `id` prop.
|
|
35
|
+
* The `overrideValue` can be a direct string (e.g., "Custom Text") or another existing `react-intl` message key (e.g., "common.cancelButton").
|
|
36
|
+
* If it's a key, `FormattedKintMessage` will attempt to format that key; otherwise, it displays the string literally.
|
|
37
|
+
* This is useful for dynamic content that might not have a static translation key or for providing specific, hardcoded text for a particular instance.
|
|
38
|
+
* As of `stripes-kint-components ^3.0.0`, `overrideValue` must be a string.
|
|
39
|
+
|
|
40
|
+
* **`fallbackMessage`**: Use this when you expect a translation to exist for your primary `id`, but you want a **graceful, silent fallback** if that translation is unexpectedly missing.
|
|
41
|
+
* This prevents `react-intl`'s default console warnings for missing messages.
|
|
42
|
+
* The `fallbackMessage` can also be a direct string or another existing `react-intl` message key.
|
|
43
|
+
* It acts as a safety net, ensuring *something* is displayed even if the primary translation isn't available.
|
|
44
|
+
|
|
45
|
+
**In summary:**
|
|
46
|
+
|
|
47
|
+
* Choose `overrideValue` for **deliberate replacement** of the translation.
|
|
48
|
+
|
|
49
|
+
* Choose `fallbackMessage` for **graceful handling of missing translations**.
|
|
50
|
+
|
|
51
|
+
```jsx
|
|
52
|
+
import { FormattedKintMessage } from '@k-int/stripes-kint-components';
|
|
53
|
+
|
|
54
|
+
const OverrideAndFallbackExample = () => (
|
|
55
|
+
<div>
|
|
56
|
+
{/* Using an overrideValue (direct string) */}
|
|
57
|
+
<FormattedKintMessage id="unimportant.key" overrideValue="This is a direct message." />
|
|
58
|
+
|
|
59
|
+
{/* Using an overrideValue (another existing intl key) */}
|
|
60
|
+
<FormattedKintMessage id="unused.key" overrideValue="someOtherIntlKey" />
|
|
61
|
+
|
|
62
|
+
{/* Using a fallbackMessage when the primary key is not found (direct string) */}
|
|
63
|
+
<FormattedKintMessage id="missing.message" fallbackMessage="Default message if not found." />
|
|
64
|
+
|
|
65
|
+
{/* Using a fallbackMessage that is itself an existing intl key */}
|
|
66
|
+
<FormattedKintMessage id="another.missing.message" fallbackMessage="common.error.generic" />
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Props
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Required | Description |
|
|
74
|
+
| :----------------------- | :--------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `fallbackMessage` | `string` | ✕ | A message or `react-intl` key to display if the primary `id` (after `intlKey` resolution) does not have a corresponding translation. This acts as a silent `defaultMessage` without console warnings. If it is a key, it will be formatted; otherwise, it will be displayed literally. |
|
|
76
|
+
| `id` | `string` | ✓ | The relative message ID to be translated. This ID is combined with the `intlKey` (resolved via `useIntlKey`) to form the full translation key. |
|
|
77
|
+
| `intlKey` | `string` | ✕ | A base internationalization key passed to the internal `useIntlKey` hook to resolve the full message path. |
|
|
78
|
+
| `intlNS` | `string` | ✕ | An internationalization namespace passed to the internal `useIntlKey` hook for resolving the full message path. |
|
|
79
|
+
| `overrideValue` | `string` | ✕ | A string value that, if present, takes precedence over all other translation logic. It can be a direct string to display or another `react-intl` message `id`. If it's a key, it will be formatted; otherwise, it will be displayed literally. **As of `stripes-kint-components ^3.0.0`, this must be a string.** |
|
|
80
|
+
| `...formattedMessageProps` | `object` | ✕ | Any additional props supported by `react-intl`'s original `FormattedMessage` component, such as `values` for injecting dynamic content into the message, `tagName`, etc. |
|
|
@@ -50,7 +50,7 @@ const NoResultsMessage = ({
|
|
|
50
50
|
iconRootClass={css.noResultsMessageIcon}
|
|
51
51
|
/>
|
|
52
52
|
}
|
|
53
|
-
<span className={css.noResultsMessageLabel}>{userLabel ?? label}</span>
|
|
53
|
+
<span className={css.noResultsMessageLabel}>{userLabel ?? labelOverrides.noResultsLabel ?? label}</span>
|
|
54
54
|
</div>
|
|
55
55
|
{/* If the filter pane is closed we show a button that toggles filter pane */}
|
|
56
56
|
{!filterPaneIsVisible && (
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# NoResultsMessage
|
|
2
|
+
|
|
3
|
+
A component that displays messages based on the state of data fetching and user interaction within lookup views.
|
|
4
|
+
**NoResultsMessage** dynamically adjusts its icon and text to indicate loading states, no results found after a search, no search terms entered, or an error during data retrieval.
|
|
5
|
+
It also provides a button to toggle the visibility of a filter pane. Generally called within context of `SASQLookupComponent -> TableBody`
|
|
6
|
+
|
|
7
|
+
## Basic Usage
|
|
8
|
+
|
|
9
|
+
Below is an example demonstrating how **NoResultsMessage** might be used within a component that manages data fetching, such as `SASQTableBody` or directly within a `MultiColumnList`'s `isEmptyMessage` prop.
|
|
10
|
+
|
|
11
|
+
```jsx
|
|
12
|
+
import { useState } from 'react';
|
|
13
|
+
import NoResultsMessage from '@k-int/stripes-kint-components/lib/NoResultsMessage';
|
|
14
|
+
|
|
15
|
+
const MyDataView = () => {
|
|
16
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
17
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
18
|
+
const [filterPaneIsVisible, setFilterPaneIsVisible] = useState(true);
|
|
19
|
+
const [isError, setIsError] = useState(false);
|
|
20
|
+
const [error, setError] = useState(null);
|
|
21
|
+
|
|
22
|
+
const toggleFilterPane = () => setFilterPaneIsVisible(prev => !prev);
|
|
23
|
+
|
|
24
|
+
// Simulate data fetching
|
|
25
|
+
useState(() => {
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
setIsLoading(false);
|
|
28
|
+
// setSearchTerm('example'); // Uncomment to simulate a search term
|
|
29
|
+
// setIsError(true); // Uncomment to simulate an error
|
|
30
|
+
// setError({ message: 'Failed to fetch data' });
|
|
31
|
+
}, 2000);
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div style={{ padding: '20px', border: '1px solid #ccc', minHeight: '200px' }}>
|
|
36
|
+
<h3>Data Display Area</h3>
|
|
37
|
+
<NoResultsMessage
|
|
38
|
+
isLoading={isLoading}
|
|
39
|
+
searchTerm={searchTerm}
|
|
40
|
+
filterPaneIsVisible={filterPaneIsVisible}
|
|
41
|
+
toggleFilterPane={toggleFilterPane}
|
|
42
|
+
isError={isError}
|
|
43
|
+
error={error}
|
|
44
|
+
// label="Custom No Results Text" // Optional: provide custom label
|
|
45
|
+
// icon="info" // Optional: provide custom icon
|
|
46
|
+
// labelOverrides={{ showFilters: 'Open Filters Panel' }} // Optional: override specific labels
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default MyDataView;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Explanation
|
|
56
|
+
|
|
57
|
+
* **isLoading:** Set to `true` when data is being fetched, displaying a loading message and spinner icon.
|
|
58
|
+
|
|
59
|
+
* **searchTerm:** Indicates whether a search term has been entered by the user. Influences the displayed message for "no results" vs. "no terms entered."
|
|
60
|
+
|
|
61
|
+
* **filterPaneIsVisible:** Controls the visibility of the "Show Filters" button.
|
|
62
|
+
|
|
63
|
+
* **toggleFilterPane:** A callback function triggered by the "Show Filters" button, typically to open the filter pane.
|
|
64
|
+
|
|
65
|
+
* **isError** and **error:** Used to display an error icon and the error message if the data fetching operation fails.
|
|
66
|
+
|
|
67
|
+
## Props
|
|
68
|
+
|
|
69
|
+
| **Prop** | **Type** | **Required** | **Description** |
|
|
70
|
+
|-----------------------|--------------------------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
71
|
+
| `filterPaneIsVisible` | `boolean` | ✓ | Indicates if the associated filter pane is currently visible. Controls the display of the "Show Filters" button. |
|
|
72
|
+
| `toggleFilterPane` | `() => void` | ✓ | Callback function invoked when the "Show Filters" button is clicked. Typically used to toggle the filter pane's visibility. |
|
|
73
|
+
| `error` | `object` | ✕ | An error object (e.g., from `react-query`) containing details of a failed request. Its `message` property will be displayed if `isError` is `true`. |
|
|
74
|
+
| `icon` | `string` | ✕ | An optional custom icon string (from `@folio/stripes/components/Icon`) to override the default icon based on the message state. |
|
|
75
|
+
| `intlKey` | `string` | ✕ | A base internationalization key used by the internal `useKintIntl` hook to resolve localized messages. |
|
|
76
|
+
| `intlNS` | `string` | ✕ | An internationalization namespace used by the internal `useKintIntl` hook. |
|
|
77
|
+
| `isLoading` | `boolean` | ✕ | When `true`, indicates that data is currently being loaded, displaying a loading message. |
|
|
78
|
+
| `isError` | `boolean` | ✕ | When `true`, indicates an error occurred during data fetching, displaying an error message. |
|
|
79
|
+
| `label` | `string`, `node`, `func` | ✕ | An optional custom label to override all default message content. |
|
|
80
|
+
| `labelOverrides` | `object` | ✕ | An object for overriding specific parts of the default labels, such as `{ noResultsLabel: 'No records found' }` or `{ showFilters: 'View Filters' }`. |
|
|
81
|
+
| `searchTerm` | `string` | ✕ | The current search query string. Used to differentiate between "no results for search" and "no search term entered" messages. |
|
|
@@ -57,29 +57,30 @@ In this example, **SASQLookupComponent**:
|
|
|
57
57
|
|
|
58
58
|
## Props
|
|
59
59
|
|
|
60
|
-
| Name | Type
|
|
61
|
-
|
|
62
|
-
| `id` | `string`
|
|
63
|
-
| `fetchParameters` | `object`
|
|
64
|
-
| `FilterComponent` | `func` or `node`
|
|
65
|
-
| `FilterPaneHeaderComponent` | `func` or `node`
|
|
66
|
-
| `filterPaneProps` | `object`
|
|
67
|
-
| `intlKey` | `string`
|
|
68
|
-
| `intlNS` | `string`
|
|
69
|
-
| `labelOverrides` | `object`
|
|
70
|
-
| `lookupQueryNamespaceGenerator` | `func`
|
|
71
|
-
| `mainPaneProps` | `object`
|
|
72
|
-
| `mclProps` | `object`
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
60
|
+
| Name | Type | Description | Default | Required |
|
|
61
|
+
|---------------------------------|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|----------|
|
|
62
|
+
| `id` | `string` | A unique identifier for the lookup instance. Used to generate unique keys for query state, persistent paneset, and filter pane visibility in local storage. | | ✓ |
|
|
63
|
+
| `fetchParameters` | `object` | An object that defines the endpoints and SASQ configuration used for fetching data. It must include:<br><br>• **endpoint:** The URL used to fetch the main data set.<br>• **SASQ_MAP:** An object containing settings for search, filter, pagination (e.g., `searchKey`, `perPage`, etc.). Additional keys (such as `itemEndpoint`) can also be provided if needed. | `{}` | ✓ |
|
|
64
|
+
| `FilterComponent` | `func` or `node` | A custom component used to render additional filtering options in the filter pane. This component receives props for managing active filters, search state, and resetting filters. | `() => null` | ✕ |
|
|
65
|
+
| `FilterPaneHeaderComponent` | `func` or `node` | A component rendered at the top of the filter pane. Use this to customize the header area of the filter pane. | `() => null` | ✕ |
|
|
66
|
+
| `filterPaneProps` | `object` | Additional props to be passed to the filter pane. These props can customize the appearance and behavior of the filter pane (such as first or last menu elements). | `{}` | ✕ |
|
|
67
|
+
| `intlKey` | `string` | A base internationalization key used by the internal `useKintIntl` hook to resolve localized messages (e.g., for labels or pane titles). | | ✕ |
|
|
68
|
+
| `intlNS` | `string` | An internationalization namespace used by the internal `useKintIntl` hook. | | ✕ |
|
|
69
|
+
| `labelOverrides` | `object` | An object for overriding default labels, such as the text for displaying the count of found values. | `{}` | ✕ |
|
|
70
|
+
| `lookupQueryNamespaceGenerator` | `func` | A function that generates a query namespace (an array) for `react-query` based on provided parameters such as `currentPage`, `namespace`, `id`, `query`, etc. This ensures that queries are uniquely identified. | See default implementation in source code | ✕ |
|
|
71
|
+
| `mainPaneProps` | `object` | Additional props to be passed to the main pane containing the lookup results. This can include custom menu elements or styling. | `{}` | ✕ |
|
|
72
|
+
| `mclProps` | `object` | Custom properties to be passed to the underlying Multi-Column List (MCL) component. These properties are merged with pagination props derived from `usePrevNextPagination`. | `{}` | ✕ |
|
|
73
|
+
| `noResultsProps` | `object` | Props to be passed down to the [NoResultsMessage](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/-/tree/main/src/lib/NoResultsMessage) splash screen component rendered when no results are present from the query. If `component` is passed, this will be rendered with the props available to `NoResultsMessage` | {} | ✕ |
|
|
74
|
+
| `noSearchField` | `bool` | When set to `true`, the search field is not rendered in the filter pane. Use this if you want to disable search input. | `false` | ✕ |
|
|
75
|
+
| `persistedPanesetProps` | `object` | Additional props to be passed to the **PersistedPaneset** component, which manages the persistent layout of the filter and main panes. | `{}` | ✕ |
|
|
76
|
+
| `queryParameterGenerator` | `func` | A function that takes the SASQ_MAP configuration and current query values to generate an array of query parameters for the fetch call. Defaults to `generateKiwtQuery`. | `generateKiwtQuery` | ✕ |
|
|
77
|
+
| `RenderBody` | `func` or `node` | A component used to render the body of the main pane (typically a table). If not provided, the internal **TableBody** component is used. | `TableBody` | ✕ |
|
|
78
|
+
| `rowNavigation` | `bool` | Flag to enable or disable row navigation. When enabled, clicking on a row triggers navigation to a detailed view. | `true` | ✕ |
|
|
79
|
+
| `sasqProps` | `object` | Additional props to override or extend the default SASQ query behavior. These props can include custom query values, setters, or getters. | | ✕ |
|
|
80
|
+
| `searchableIndexes` | `arrayOf(object)` | An array of objects defining the options for the search index selection component (`SearchKeyControl`), rendered below the search field. Each object typically has `value` and `label` keys. If empty or omitted, the qindex checkboxes are not shown. | `[]` | ✕ |
|
|
81
|
+
| `searchFieldAriaLabel` | `string` | Accessibility label for the search field. | | ✕ |
|
|
82
|
+
| `searchFieldProps` | `object` | Additional props to be passed to the **SearchField** component for customizing its behavior or styling. | | ✕ |
|
|
83
|
+
| `children` | `node`, `func` | Optional children to be rendered below the main pane. These are rendered within the **PersistedPaneset** container. | | ✕ |
|
|
83
84
|
Below is an additional section for **SASQLookupComponent** documentation that describes the available functionality on the component's ref along with a worked example.
|
|
84
85
|
|
|
85
86
|
|
|
@@ -54,6 +54,7 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
54
54
|
},
|
|
55
55
|
mainPaneProps = {},
|
|
56
56
|
mclProps = {},
|
|
57
|
+
noResultsProps = {},
|
|
57
58
|
noSearchField,
|
|
58
59
|
persistedPanesetProps = {},
|
|
59
60
|
queryParameterGenerator = generateKiwtQuery, // Expects a function which accepts SASQ_MAP and nsValues
|
|
@@ -304,6 +305,7 @@ const SASQLookupComponent = forwardRef((props, ref) => {
|
|
|
304
305
|
intlKey={passedIntlKey}
|
|
305
306
|
intlNS={passedIntlNS}
|
|
306
307
|
labelOverrides={labelOverrides}
|
|
308
|
+
noResultsProps={noResultsProps}
|
|
307
309
|
query={query}
|
|
308
310
|
rowNavigation={rowNavigation}
|
|
309
311
|
toggleFilterPane={toggleFilterPane}
|
|
@@ -61,24 +61,25 @@ export default MyTableView;
|
|
|
61
61
|
|
|
62
62
|
## Props
|
|
63
63
|
|
|
64
|
-
| Prop | Type | Required | Description
|
|
65
|
-
|
|
66
|
-
| `data` | `{ totalRecords: number, results: object[] }` | ✓ | Data to display. `results` contains the items, `totalRecords` sets pagination bounds.
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
-
| `
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
64
|
+
| Prop | Type | Required | Description |
|
|
65
|
+
|---------------------|--------------------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
66
|
+
| `data` | `{ totalRecords: number, results: object[] }` | ✓ | Data to display. `results` contains the items, `totalRecords` sets pagination bounds. |
|
|
67
|
+
| `error` | `object` | ✕ | Error object displayed in `NoResultsMessage`. |
|
|
68
|
+
| `fetchNextPage` | `({ pageParam: number }) => void` | ✓ | Callback to load more data. `pageParam` indicates the next page index. |
|
|
69
|
+
| `filterPaneVisible` | `boolean` | ✕ | Toggles filter pane visibility in `NoResultsMessage`. |
|
|
70
|
+
| `intlKey` | `string` | ✕ | Base key for internationalizing labels. See `useKintIntl`. |
|
|
71
|
+
| `intlNS` | `string` | ✕ | Namespace for internationalization. See `useKintIntl`. |
|
|
72
|
+
| `isError` | `boolean` | ✕ | Shows error state in `NoResultsMessage`. |
|
|
73
|
+
| `isLoading` | `boolean` | ✕ | Shows loading state in `NoResultsMessage`. |
|
|
74
|
+
| `labelOverrides` | `object` | ✕ | Overrides default labels (e.g., `{ noResultsFound: 'No items' }`). |
|
|
75
|
+
| `match` | `object` | ✕ | React Router `match` object. Used to highlight the selected row via URL `id` param. |
|
|
76
|
+
| `mclProps` | `object` | ✕ | Props passed to the underlying [MultiColumnList](https://github.com/folio-org/stripes-components/tree/master/lib/MultiColumnList). Example: `formatter`, `id`. |
|
|
77
|
+
| `noResultsProps` | `object` | ✕ | Props to be passed down to the [NoResultsMessage](https://gitlab.com/knowledge-integration/folio/stripes-kint-components/-/tree/main/src/lib/NoResultsMessage) splash screen component rendered when no results are present from the query. If `component` is passed, this will be rendered with the props available to `NoResultsMessage` |
|
|
78
|
+
| `path` | `string` | ✓ | Base path for row URLs. Each row links to `{path}/{rowData.id}`. |
|
|
79
|
+
| `query` | `object` | ✓ | Current query state (e.g., `{ sort: 'name', query: 'search term' }`). Used for sorting and empty state messages. |
|
|
80
|
+
| `resultColumns` | `Array<{ propertyPath: string, label: string }>` | ✓ | Columns to render. `propertyPath` accesses the data field, `label` sets the header. |
|
|
81
|
+
| `rowNavigation` | `boolean` | ✕ | Enables navigation to detail views on row click. Default: `true`. |
|
|
82
|
+
| `toggleFilterPane` | `() => void` | ✕ | Callback to toggle filter pane. Used in `NoResultsMessage`. |
|
|
82
83
|
|
|
83
84
|
## Key Features
|
|
84
85
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
|
|
4
4
|
import { useHistory, useLocation } from 'react-router-dom';
|
|
@@ -23,6 +23,7 @@ const TableBody = ({
|
|
|
23
23
|
formatter = {},
|
|
24
24
|
...mclProps
|
|
25
25
|
} = {},
|
|
26
|
+
noResultsProps = {},
|
|
26
27
|
onSort,
|
|
27
28
|
path,
|
|
28
29
|
resultColumns,
|
|
@@ -76,6 +77,7 @@ const TableBody = ({
|
|
|
76
77
|
}, [getRowUrl, history, rowNavigation]);
|
|
77
78
|
|
|
78
79
|
const isSelected = useCallback(({ item }) => item.id === match?.params?.id, [match?.params?.id]);
|
|
80
|
+
const NoResultsComponent = useMemo(() => noResultsProps?.component ?? NoResultsMessage, [noResultsProps?.component]);
|
|
79
81
|
|
|
80
82
|
return (
|
|
81
83
|
<MultiColumnList
|
|
@@ -86,7 +88,7 @@ const TableBody = ({
|
|
|
86
88
|
hasMargin
|
|
87
89
|
interactive={rowNavigation}
|
|
88
90
|
isEmptyMessage={
|
|
89
|
-
<
|
|
91
|
+
<NoResultsComponent
|
|
90
92
|
{...{
|
|
91
93
|
error,
|
|
92
94
|
filterPaneIsVisible: filterPaneVisible,
|
|
@@ -96,7 +98,8 @@ const TableBody = ({
|
|
|
96
98
|
isLoading,
|
|
97
99
|
labelOverrides,
|
|
98
100
|
searchTerm: query.query,
|
|
99
|
-
toggleFilterPane
|
|
101
|
+
toggleFilterPane,
|
|
102
|
+
...noResultsProps, // Anything passed in directly takes precedence
|
|
100
103
|
}}
|
|
101
104
|
/>
|
|
102
105
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# SearchKeyControl
|
|
2
2
|
|
|
3
|
-
A component that renders a group of checkboxes allowing users to select one or more search keys (indexes). It
|
|
3
|
+
A component that renders a group of checkboxes allowing users to select one or more search keys (indexes). It synchronizes its state with the `qIndex` URL parameter (managed via the `useQIndex` hook), updating this parameter by injecting or removing individual keys based on user interactions.
|
|
4
4
|
|
|
5
|
-
> **Note:** This component is
|
|
5
|
+
> **Note:** This component is **controlled by the `qIndex` URL parameter** rather than external props like `value` or `onChange`. When users interact with checkboxes, the component modifies the `qIndex` by adding or removing search keys accordingly. It **does not** replace the entire `qIndex` value.
|
|
6
|
+
|
|
7
|
+
---
|
|
6
8
|
|
|
7
9
|
## Basic Usage
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Provide an `options` array with each search key to be rendered. Each option includes a `key`, a display `label`, and optionally, an `indexes` array to represent multiple underlying sub-indexes.
|
|
10
12
|
|
|
11
13
|
```jsx
|
|
12
14
|
import { SearchKeyControl } from '@k-int/stripes-kint-components';
|
|
@@ -16,55 +18,78 @@ const MySearchForm = () => {
|
|
|
16
18
|
{ key: 'keyword', label: 'Keyword' },
|
|
17
19
|
{ key: 'title', label: 'Title' },
|
|
18
20
|
{ key: 'author', label: 'Author' },
|
|
19
|
-
{
|
|
21
|
+
{
|
|
22
|
+
key: 'subjectPlus',
|
|
23
|
+
label: 'Subject (incl. subdivisions)',
|
|
24
|
+
indexes: ['subject', 'subdivision']
|
|
25
|
+
}
|
|
20
26
|
];
|
|
21
27
|
|
|
22
28
|
return (
|
|
23
29
|
<div>
|
|
24
|
-
{/* ... other search form elements ... */}
|
|
25
30
|
<label>Search Indexes:</label>
|
|
26
31
|
<SearchKeyControl options={searchKeyOptions} />
|
|
27
|
-
{/* ... submit button etc ... */}
|
|
28
32
|
</div>
|
|
29
33
|
);
|
|
30
34
|
};
|
|
31
35
|
|
|
32
36
|
export default MySearchForm;
|
|
33
|
-
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
In this example:
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
* **Checkboxes** are rendered for each `key`, including the composite `subjectPlus`.
|
|
42
|
+
* The `qIndex` URL parameter (e.g. `?qIndex=title,author`) determines the checked state.
|
|
43
|
+
* Clicking a checkbox adds or removes the relevant index or indexes:
|
|
36
44
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- It also automatically resets pagination (via `usePrevNextPagination`) when the `qIndex` changes.
|
|
45
|
+
* For simple entries like `"title"`, toggling directly modifies `qIndex`.
|
|
46
|
+
* For composite entries like `"subjectPlus"`, checking adds both `"subject"` and `"subdivision"`; unchecking removes both.
|
|
47
|
+
* **Pagination is reset** automatically via `usePrevNextPagination()` when the `qIndex` changes.
|
|
48
|
+
|
|
49
|
+
---
|
|
43
50
|
|
|
44
51
|
## Props
|
|
45
52
|
|
|
46
|
-
| Name | Type | Description
|
|
47
|
-
|
|
48
|
-
| `options` | `arrayOf(object)` |
|
|
53
|
+
| Name | Type | Description | Default | Required |
|
|
54
|
+
| :-------- | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------ | :------- |
|
|
55
|
+
| `options` | `arrayOf(object)` | Array of search key definitions. Each object must include:<br>• `key` (string): A unique identifier.<br>• `label` (string \| node): The displayed label.<br>• `indexes` (array of strings, optional): One or more sub-indexes that this checkbox controls (defaults to `[key]` if omitted). | `[]` | ✕ |
|
|
49
56
|
|
|
57
|
+
---
|
|
50
58
|
|
|
51
59
|
## How It Works
|
|
52
60
|
|
|
53
|
-
1.
|
|
54
|
-
|
|
61
|
+
### 1. Reading Search Index State
|
|
62
|
+
|
|
63
|
+
The component uses `useQIndex()` to retrieve and manage the `qIndex` URL parameter. The value is split into an array of active keys (`qIndexArray`), trimmed for whitespace and memoized.
|
|
64
|
+
|
|
65
|
+
### 2. Creating Internal State
|
|
66
|
+
|
|
67
|
+
A `keyState` object maps each option's `key` to:
|
|
68
|
+
|
|
69
|
+
* `inUse`: A boolean indicating whether all of the entry’s `indexes` are present in `qIndexArray`.
|
|
70
|
+
* `label`: The label to display next to the checkbox.
|
|
71
|
+
* `subIndexes`: The underlying `indexes` array (or `[key]` if not specified).
|
|
72
|
+
|
|
73
|
+
This mapping is memoized via `useCallback()` and kept in sync with URL state using `useEffect()`.
|
|
74
|
+
|
|
75
|
+
### 3. Rendering Checkboxes
|
|
76
|
+
|
|
77
|
+
Each `keyState` entry is rendered as a checkbox using `@folio/stripes/components`' `Checkbox`. Its `checked` state is tied to `inUse`, and its `label` comes from the `label` field.
|
|
78
|
+
|
|
79
|
+
### 4. Handling Changes
|
|
80
|
+
|
|
81
|
+
On user interaction:
|
|
82
|
+
|
|
83
|
+
* If a checkbox is checked:
|
|
84
|
+
|
|
85
|
+
* The component **adds** all `subIndexes` for the key to the `qIndexArray`.
|
|
86
|
+
* If a checkbox is unchecked:
|
|
55
87
|
|
|
56
|
-
|
|
57
|
-
It uses `useState`, `useEffect`, `useMemo`, and `useCallback` along with `lodash/isEqual` to create and maintain an internal `keyState` object. This object maps each `key` from the `options` prop to its display `label` and an `inUse` boolean flag. The `inUse` flag is determined by checking if the option's `key` exists within the current `qIndexArray` derived from the `qIndex` URL parameter. This ensures the checkboxes visually reflect the state in the URL.
|
|
88
|
+
* The component **removes** all `subIndexes` for the key from `qIndexArray`.
|
|
58
89
|
|
|
59
|
-
|
|
60
|
-
The component iterates over the `keyState` object and renders a `@folio/stripes/components` `Checkbox` for each entry. The `checked` prop of the checkbox is bound to the `inUse` flag from `keyState`, and the `label` is set accordingly.
|
|
90
|
+
The updated array is joined back into a comma-separated string and passed to `setQIndex()` to update the URL.
|
|
61
91
|
|
|
62
|
-
|
|
63
|
-
When a checkbox's state is changed by the user:
|
|
92
|
+
### 5. Pagination Reset
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
* It updates a temporary copy of the `qIndexArray` (either adding the key with `push` or removing it with `splice`).
|
|
67
|
-
* It calls `setQIndex` (from `useQIndex`) with the modified array joined back into a comma-separated string, which updates the URL parameter.
|
|
94
|
+
If the current page is non-zero (via `usePrevNextPagination`), the component calls `resetPage()` after modifying `qIndex`. This ensures consistency in result navigation after a filter change.
|
|
68
95
|
|
|
69
|
-
5. **Pagination Reset:**
|
|
70
|
-
The component also uses the `usePrevNextPagination` hook. If pagination is active (`currentPage` has a value), it calls `resetPage()` after updating the `qIndex`. This ensures that users are returned to the first page of results when the search indexes change, preventing potentially invalid page numbers for the new search scope.
|
|
@@ -23,7 +23,14 @@ const SearchKeyControl = ({
|
|
|
23
23
|
// Memoise this process so keyState changes if and only if options/qIndex change
|
|
24
24
|
const createKeyState = useCallback(() => (
|
|
25
25
|
options.reduce((acc, curr) => {
|
|
26
|
-
|
|
26
|
+
// Is in use if URL contains ALL of the indexes
|
|
27
|
+
const subindexes = ((curr?.indexes?.length ?? 0) > 0) ? curr.indexes : [curr.key];
|
|
28
|
+
|
|
29
|
+
acc[curr.key] = {
|
|
30
|
+
inUse: subindexes.every(si => qIndexArray.includes(si)),
|
|
31
|
+
label: curr.label ?? curr.key,
|
|
32
|
+
subIndexes: curr.indexes
|
|
33
|
+
};
|
|
27
34
|
return acc;
|
|
28
35
|
}, {})
|
|
29
36
|
), [options, qIndexArray]);
|
|
@@ -41,6 +48,31 @@ const SearchKeyControl = ({
|
|
|
41
48
|
// Check to see if page param exists, and if it does then changing qIndex should reset it
|
|
42
49
|
const { currentPage, resetPage } = usePrevNextPagination({ defaultToPageOne: false });
|
|
43
50
|
|
|
51
|
+
const handleSearchKeyChange = useCallback(({ e: { target: { checked: targetIsChecked } = {} } = {}, key, value }) => {
|
|
52
|
+
// Set up which indexes need to change
|
|
53
|
+
const indicesToChange = ((value?.subIndexes?.length ?? 0) > 0) ? value.subIndexes : [key];
|
|
54
|
+
|
|
55
|
+
// If false, we must remove from the qIndex
|
|
56
|
+
if (!targetIsChecked) {
|
|
57
|
+
indicesToChange.forEach(ind => {
|
|
58
|
+
const indexOfKey = qIndexArray.indexOf(ind);
|
|
59
|
+
if (indexOfKey > -1) { // only splice array when item is found
|
|
60
|
+
qIndexArray.splice(indexOfKey, 1); // 2nd parameter means remove one item only
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
// If true, we need to add to qIndex
|
|
65
|
+
indicesToChange.forEach(ind => {
|
|
66
|
+
qIndexArray.push(ind);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setQIndex(qIndexArray?.join(','));
|
|
71
|
+
if (currentPage) {
|
|
72
|
+
resetPage();
|
|
73
|
+
}
|
|
74
|
+
}, [currentPage, qIndexArray, resetPage, setQIndex]);
|
|
75
|
+
|
|
44
76
|
return (
|
|
45
77
|
<>
|
|
46
78
|
<div className={css.searchKeyControlContainer}>
|
|
@@ -59,23 +91,7 @@ const SearchKeyControl = ({
|
|
|
59
91
|
checked={value?.inUse}
|
|
60
92
|
className={css.searchKeyControlElement}
|
|
61
93
|
label={value?.label}
|
|
62
|
-
onChange={e => {
|
|
63
|
-
// If false, we must remove from the qIndex
|
|
64
|
-
if (!e.target.checked) {
|
|
65
|
-
const indexOfKey = qIndexArray.indexOf(key);
|
|
66
|
-
if (indexOfKey > -1) { // only splice array when item is found
|
|
67
|
-
qIndexArray.splice(indexOfKey, 1); // 2nd parameter means remove one item only
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
// If true, we need to add to qIndex
|
|
71
|
-
qIndexArray.push(key);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
setQIndex(qIndexArray?.join(','));
|
|
75
|
-
if (currentPage) {
|
|
76
|
-
resetPage();
|
|
77
|
-
}
|
|
78
|
-
}}
|
|
94
|
+
onChange={e => handleSearchKeyChange({ e, key, value })}
|
|
79
95
|
/>
|
|
80
96
|
);
|
|
81
97
|
})
|