+ {options.map(({ label: radioBtnLabel, value }, i) => {
+ const isChecked = value === (activeFilters[name] || defaultValue);
+
+ return (
+ {
+ const replaced = {
+ ...activeFilters,
+ // if this option is a default, clear the filter
+ [name]: value === defaultValue ? undefined : value
+ };
+ const withoutDefault = filter(item => item.value !== undefined, replaced);
+
+ return onUpdate(withoutDefault);
+ }}
+ />
+ );
+ })}
+
+ );
+ };
+
return (
{
const accordionLabelId = `filter-${searchType}-${name}-label`;
+ const radioGroupProps = {
+ name,
+ options,
+ accordionLabelId,
+ defaultValue,
+ label,
+ };
+
+ if (!hasAccordion) {
+ const hasSelectedOption = ![undefined, defaultValue].includes(activeFilters[name]);
+
+ return (
+
+
+
+ handleClearButtonClick(accordionLabelId, name)}
+ />
+
+ {renderRadioGroup(radioGroupProps)}
+
+ );
+ }
+
return (
onUpdate({ ...activeFilters, [name]: undefined })}
+ onClearFilter={() => handleClearFilter(name)}
id={`filter-${searchType}-${name}`}
className={styles['search-filter-accordion']}
>
-
- {options.map(({ label: radioBtnLabel, value }, i) => {
- const isChecked = value === (activeFilters[name] || defaultValue);
-
- return (
- {
- const replaced = {
- ...activeFilters,
- // if this option is a default, clear the filter
- [name]: value === defaultValue ? undefined : value
- };
- const withoutDefault = filter(item => item.value !== undefined, replaced);
-
- return onUpdate(withoutDefault);
- }}
- />
- );
- })}
-
+ {renderRadioGroup(radioGroupProps)}
);
})}
diff --git a/src/components/search-form/search-form.css b/src/components/search-form/search-form.css
index a4cda3282..09339ada1 100644
--- a/src/components/search-form/search-form.css
+++ b/src/components/search-form/search-form.css
@@ -23,3 +23,16 @@
.search-field {
margin-bottom: calc(var(--control-margin-bottom) / 2);
}
+
+.groupContainer {
+ margin-bottom: 1rem;
+}
+
+.clearButton {
+ margin-bottom: var(--control-label-margin-bottom);
+}
+
+.groupTitle {
+ display: flex;
+ align-items: center;
+}
diff --git a/src/components/search-modal/search-modal.js b/src/components/search-modal/search-modal.js
index 2262bb7e0..ddf738e32 100644
--- a/src/components/search-modal/search-modal.js
+++ b/src/components/search-modal/search-modal.js
@@ -19,21 +19,10 @@ import {
accessTypesReduxStateShape,
searchTypes,
} from '../../constants';
-import { filterCountFromQuery } from '../utilities';
-
-export const normalize = (query = {}) => {
- return {
- filter: query.filter || {
- tags: undefined,
- type: undefined,
- selected: undefined,
- 'access-type': undefined,
- },
- q: query.q || '',
- searchfield: query.searchfield,
- sort: query.sort,
- };
-};
+import {
+ filterCountFromQuery,
+ normalize,
+} from '../utilities';
class SearchModal extends PureComponent {
static propTypes = {
diff --git a/src/components/search-section/action-menu/action-menu.css b/src/components/search-section/action-menu/action-menu.css
new file mode 100644
index 000000000..e5be30c25
--- /dev/null
+++ b/src/components/search-section/action-menu/action-menu.css
@@ -0,0 +1,5 @@
+.actionMenuToggle {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
diff --git a/src/components/search-section/action-menu/action-menu.js b/src/components/search-section/action-menu/action-menu.js
new file mode 100644
index 000000000..ccdf5f092
--- /dev/null
+++ b/src/components/search-section/action-menu/action-menu.js
@@ -0,0 +1,239 @@
+import {
+ FormattedMessage,
+ useIntl,
+} from 'react-intl';
+import PropTypes from 'prop-types';
+import sortBy from 'lodash/sortBy';
+
+import {
+ Badge,
+ Button,
+ DropdownMenu,
+ Icon,
+ Tooltip,
+ Dropdown,
+} from '@folio/stripes/components';
+import { IfPermission } from '@folio/stripes/core';
+
+import { TagsFilter } from '../../tags-filter';
+import { AccessTypesFilter } from '../../access-type-filter';
+import PackageSearchFilters from '../../package-search-filters';
+import ProviderSearchFilters from '../../provider-search-filters';
+import TitleSearchFilters from '../../title-search-filters';
+import {
+ getAccessTypesList,
+ getTagLabelsArr,
+ getTagsList,
+} from '../../utilities';
+import { searchTypes } from '../../../constants';
+
+import styles from './action-menu.css';
+
+const searchFiltersComponents = {
+ [searchTypes.PACKAGES]: PackageSearchFilters,
+ [searchTypes.PROVIDERS]: ProviderSearchFilters,
+ [searchTypes.TITLES]: TitleSearchFilters,
+};
+
+const propTypes = {
+ accessTypes: PropTypes.object.isRequired,
+ filterCount: PropTypes.number.isRequired,
+ onFilterChange: PropTypes.func.isRequired,
+ onStandaloneFilterChange: PropTypes.func.isRequired,
+ onToggleActions: PropTypes.func.isRequired,
+ onToggleFilter: PropTypes.func.isRequired,
+ packagesFacetCollection: PropTypes.object,
+ params: PropTypes.object,
+ prevDataOfOptedPackage: PropTypes.object,
+ query: PropTypes.object.isRequired,
+ results: PropTypes.object,
+ searchByAccessTypesEnabled: PropTypes.bool.isRequired,
+ searchByTagsEnabled: PropTypes.bool.isRequired,
+ searchType: PropTypes.string.isRequired,
+ standaloneFiltersEnabled: PropTypes.bool.isRequired,
+ tagsModelOfAlreadyAddedTags: PropTypes.object.isRequired,
+ titlesFacets: PropTypes.object,
+};
+
+const ActionMenu = ({
+ searchType,
+ tagsModelOfAlreadyAddedTags,
+ searchByTagsEnabled,
+ searchByAccessTypesEnabled,
+ query,
+ accessTypes,
+ standaloneFiltersEnabled,
+ params,
+ prevDataOfOptedPackage,
+ results,
+ titlesFacets,
+ packagesFacetCollection,
+ filterCount,
+ onFilterChange,
+ onToggleFilter,
+ onToggleActions,
+ onStandaloneFilterChange,
+}) => {
+ const intl = useIntl();
+
+ const Filters = searchFiltersComponents[searchType];
+
+ // sort is treated separately from the rest of the filters on submit,
+ // but treated together when rendering the filters.
+ const combinedFilters = {
+ sort: query.sort,
+ ...query.filter,
+ };
+
+ const handleStandaloneFilterChange = filter => {
+ const formattedFilter = {
+ [filter.name]: filter.values || undefined,
+ };
+
+ onStandaloneFilterChange(formattedFilter);
+ };
+
+ const getSortedDataOptions = () => {
+ const dataOptions = getTagLabelsArr(tagsModelOfAlreadyAddedTags)
+ .filter(tag => tag.value)
+ .map(tag => {
+ const tagDisplay = tag.value.toLowerCase();
+
+ return {
+ value: tagDisplay,
+ label: tagDisplay,
+ };
+ });
+
+ return sortBy(dataOptions, ['value']);
+ };
+
+ const renderAccessTypesFilter = () => {
+ const accessStatusTypesExist = !!accessTypes?.items?.data?.length;
+ const isPackagesOrTitlesSearchType = [searchTypes.PACKAGES, searchTypes.TITLES].includes(searchType);
+
+ const accessTypesDataOptions = accessTypes?.items?.data?.map(({ attributes }) => ({
+ value: attributes.name,
+ label: attributes.name,
+ }));
+
+ if (isPackagesOrTitlesSearchType && accessStatusTypesExist) {
+ return (
+
+ );
+ }
+
+ return null;
+ };
+
+ const renderActionMenu = () => {
+ const tagsOptions = getSortedDataOptions();
+
+ return (
+
+
+
+
+ {renderAccessTypesFilter()}
+
+
+ );
+ };
+
+ const renderActionMenuContent = () => (
+
+ {renderActionMenu()}
+
+ );
+
+ const renderActionMenuToggle = ({ onToggle, triggerRef, keyHandler, open, ariaProps, getTriggerProps }) => {
+ const handleActionMenuToggle = (e) => {
+ onToggleActions(!open);
+ onToggle(e);
+ };
+
+ return (
+
+
+ {filterCount > 0 && (
+
+ {({ ref, ariaIds }) => (
+
+
+ {filterCount}
+
+
+ )}
+
+ )}
+
+ );
+ };
+
+ return (
+
+ );
+};
+
+ActionMenu.propTypes = propTypes;
+
+export { ActionMenu };
diff --git a/src/components/search-section/action-menu/index.js b/src/components/search-section/action-menu/index.js
new file mode 100644
index 000000000..19707d5d0
--- /dev/null
+++ b/src/components/search-section/action-menu/index.js
@@ -0,0 +1 @@
+export * from './action-menu';
diff --git a/src/components/search-section/index.js b/src/components/search-section/index.js
new file mode 100644
index 000000000..38e12c211
--- /dev/null
+++ b/src/components/search-section/index.js
@@ -0,0 +1 @@
+export * from './search-section';
diff --git a/src/components/search-section/search-section.css b/src/components/search-section/search-section.css
new file mode 100644
index 000000000..54423ad8c
--- /dev/null
+++ b/src/components/search-section/search-section.css
@@ -0,0 +1,4 @@
+.container {
+ display: flex;
+ gap: 1rem;
+}
diff --git a/src/components/search-section/search-section.js b/src/components/search-section/search-section.js
new file mode 100644
index 000000000..9042801e3
--- /dev/null
+++ b/src/components/search-section/search-section.js
@@ -0,0 +1,221 @@
+import {
+ useRef,
+ useState,
+} from 'react';
+import { useIntl } from 'react-intl';
+import PropTypes from 'prop-types';
+
+import {
+ SearchField,
+ Select
+} from '@folio/stripes/components';
+
+import { ActionMenu } from './action-menu';
+import {
+ searchableIndexes,
+ searchTypes,
+} from '../../constants';
+import {
+ filterCountFromQuery,
+ normalize,
+} from '../utilities';
+
+import styles from './search-section.css';
+
+const EMPTY_OBJECT = {};
+
+const propTypes = {
+ accessTypes: PropTypes.object.isRequired,
+ onFilter: PropTypes.func.isRequired,
+ onToggleActions: PropTypes.func.isRequired,
+ packagesFacetCollection: PropTypes.object,
+ params: PropTypes.object,
+ prevDataOfOptedPackage: PropTypes.object,
+ queryProp: PropTypes.object.isRequired,
+ results: PropTypes.object,
+ searchType: PropTypes.string.isRequired,
+ tagsModelOfAlreadyAddedTags: PropTypes.object,
+ titlesFacets: PropTypes.object,
+};
+
+const SearchSection = ({
+ searchType,
+ queryProp,
+ tagsModelOfAlreadyAddedTags,
+ accessTypes,
+ params = EMPTY_OBJECT,
+ prevDataOfOptedPackage = EMPTY_OBJECT,
+ results = EMPTY_OBJECT,
+ titlesFacets = EMPTY_OBJECT,
+ packagesFacetCollection = EMPTY_OBJECT,
+ onFilter,
+ onToggleActions,
+}) => {
+ const intl = useIntl();
+
+ const queryContainsTagsFilter = !!queryProp?.filter?.tags;
+ const queryContainsAccessTypesFilter = !!queryProp?.filter['access-type'];
+
+ const searchFieldRef = useRef(null);
+ const [query, setQuery] = useState(normalize(queryProp));
+ const [searchByTagsEnabled, setSearchByTagsEnabled] = useState(queryContainsTagsFilter);
+ const [searchByAccessTypesEnabled, setSearchByAccessTypesEnabled] = useState(queryContainsAccessTypesFilter && !queryContainsTagsFilter);
+
+ const standaloneFiltersEnabled = searchByTagsEnabled || searchByAccessTypesEnabled;
+ const queryFromProps = normalize(queryProp);
+ const filterCount = filterCountFromQuery(queryFromProps);
+
+ const updateFilter = (_query) => {
+ let searchQuery;
+
+ if (!searchByTagsEnabled && _query.q !== '') {
+ searchQuery = _query.q;
+ }
+
+ const filter = { ..._query.filter };
+
+ if (!searchByTagsEnabled) {
+ filter.tags = undefined;
+ }
+
+ if (!searchByAccessTypesEnabled) {
+ filter['access-type'] = undefined;
+ }
+
+ onFilter({
+ ..._query,
+ filter,
+ q: searchQuery,
+ });
+ };
+
+ const handleSearchSubmit = (e) => {
+ e.preventDefault();
+ updateFilter(query);
+ };
+
+ const handleSearchFieldChange = (e) => {
+ setQuery(cur => normalize({
+ ...cur,
+ searchfield: e.target.value,
+ }));
+ };
+
+ const handleSearchQueryChange = e => {
+ setQuery(cur => ({
+ ...cur,
+ q: e.target.value,
+ }));
+ };
+
+ const handleClearSearch = () => {
+ setQuery(cur => ({
+ ...cur,
+ q: '',
+ }));
+ };
+
+ const toggleFilter = filterName => () => {
+ if (filterName === 'access-type') {
+ setSearchByAccessTypesEnabled(cur => !cur);
+ setSearchByTagsEnabled(false);
+ } else {
+ setSearchByTagsEnabled(cur => !cur);
+ setSearchByAccessTypesEnabled(false);
+ }
+ };
+
+ const handleStandaloneFilterChange = filter => {
+ setQuery(cur => {
+ const newQuery = normalize({
+ sort: cur.sort,
+ filter,
+ });
+
+ updateFilter(newQuery);
+
+ return newQuery;
+ });
+ };
+
+ const handleFilterChange = (args) => {
+ const { sort, ...filter } = args;
+
+ setQuery(cur => {
+ const newQuery = normalize({
+ sort,
+ filter,
+ searchfield: cur.searchfield,
+ q: cur.q,
+ });
+
+ updateFilter(newQuery);
+
+ return newQuery;
+ });
+ };
+
+ return (
+
+ {searchType === searchTypes.TITLES && (
+
+ )}
+
+
+
+ );
+};
+
+SearchSection.propTypes = propTypes;
+
+export { SearchSection };
diff --git a/src/components/search-section/search-section.test.js b/src/components/search-section/search-section.test.js
new file mode 100644
index 000000000..110123b78
--- /dev/null
+++ b/src/components/search-section/search-section.test.js
@@ -0,0 +1,123 @@
+import { act } from 'react';
+
+import { render } from '@folio/jest-config-stripes/testing-library/react';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
+
+import { SearchSection } from './search-section';
+import {
+ searchableIndexes,
+ searchTypes,
+} from '../../constants';
+
+const mockOnFilter = jest.fn();
+
+const queryProp = {
+ searchfield: 'title',
+ count: 100,
+ page: 1,
+ filter: {
+ 'access-type': undefined,
+ selected: undefined,
+ tags: undefined,
+ type: undefined,
+ },
+};
+
+const accessTypes = {
+ isLoading: false,
+ items: {
+ data: [],
+ meta: {
+ totalResults: 0
+ },
+ jsonapi: {
+ version: '1.0',
+ },
+ },
+ errors: [],
+ isDeleted: false
+};
+
+const tagsModelOfAlreadyAddedTags = {
+ isLoading: false,
+};
+
+const renderSearchSection = (props = {}) => render(
+
+);
+
+describe('SearchSection', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should render search box', () => {
+ const { getByRole } = renderSearchSection();
+
+ expect(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' })).toBeInTheDocument();
+ });
+
+ describe('when search option changes', () => {
+ it('should not fetch data', async () => {
+ const { getByRole } = renderSearchSection();
+
+ await userEvent.selectOptions(getByRole('combobox'), searchableIndexes.ISNX);
+
+ expect(mockOnFilter).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when search query changes', () => {
+ it('should not fetch data', async () => {
+ const { getByRole } = renderSearchSection();
+
+ await userEvent.type(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' }), 'Test query');
+
+ expect(mockOnFilter).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when search is submitted', () => {
+ it('should fetch data', async () => {
+ const { getByRole } = renderSearchSection();
+
+ const searchBox = getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' });
+
+ await act(() => userEvent.type(searchBox, 'Title name{enter}'));
+
+ expect(mockOnFilter).toHaveBeenCalledWith(expect.objectContaining({ q: 'Title name' }));
+ });
+ });
+
+ describe('when hitting clear icon', () => {
+ it('should clear search box', async () => {
+ const { getByRole } = renderSearchSection();
+
+ const searchBox = getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' });
+
+ await userEvent.type(searchBox, 'Title name');
+ await userEvent.click(getByRole('button', { name: 'stripes-components.clearThisField' }));
+
+ expect(searchBox.value).toBe('');
+ });
+ });
+
+ describe('when search by tags filter is enabled', () => {
+ it('should disable search box', async () => {
+ const { getByText, getByRole } = renderSearchSection();
+
+ expect(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' })).toBeEnabled();
+
+ await userEvent.click(getByText('ui-eholdings.search.searchByTagsOnly'));
+
+ expect(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' })).toBeDisabled();
+ });
+ });
+});
diff --git a/src/components/tags-filter/index.js b/src/components/tags-filter/index.js
new file mode 100644
index 000000000..50a466333
--- /dev/null
+++ b/src/components/tags-filter/index.js
@@ -0,0 +1 @@
+export * from './tags-filter';
diff --git a/src/components/tags-filter/tags-filter.css b/src/components/tags-filter/tags-filter.css
new file mode 100644
index 000000000..1fcd1b4d3
--- /dev/null
+++ b/src/components/tags-filter/tags-filter.css
@@ -0,0 +1,4 @@
+.headline {
+ display: flex;
+ align-items: baseline;
+}
diff --git a/src/components/tags-filter/tags-filter.js b/src/components/tags-filter/tags-filter.js
new file mode 100644
index 000000000..7c9278f73
--- /dev/null
+++ b/src/components/tags-filter/tags-filter.js
@@ -0,0 +1,88 @@
+import { useRef } from 'react';
+import PropTypes from 'prop-types';
+import { useIntl } from 'react-intl';
+
+import { MultiSelectionFilter } from '@folio/stripes/smart-components';
+
+import { ClearButton } from '../clear-button';
+import { SearchByCheckbox } from '../search-by-checkbox';
+
+import styles from './tags-filter.css';
+
+const propTypes = {
+ dataOptions: PropTypes.arrayOf(PropTypes.shape({
+ label: PropTypes.string,
+ value: PropTypes.string,
+ })).isRequired,
+ handleStandaloneFilterChange: PropTypes.func.isRequired,
+ isLoading: PropTypes.object.isRequired,
+ onStandaloneFilterChange: PropTypes.func.isRequired,
+ onStandaloneFilterToggle: PropTypes.func.isRequired,
+ searchByTagsEnabled: PropTypes.bool.isRequired,
+ selectedValues: PropTypes.object.isRequired,
+ showClearButton: PropTypes.bool,
+};
+
+const TagsFilter = ({
+ isLoading,
+ selectedValues,
+ searchByTagsEnabled,
+ onStandaloneFilterChange,
+ onStandaloneFilterToggle,
+ handleStandaloneFilterChange,
+ dataOptions,
+ showClearButton = false,
+}) => {
+ const intl = useIntl();
+ const labelRef = useRef(null);
+
+ const tagsFilterLabel = intl.formatMessage({ id: 'ui-eholdings.tags.filter' });
+
+ const handleClearButtonClick = () => {
+ onStandaloneFilterChange({ tags: undefined });
+ labelRef.current?.focus();
+ };
+
+ return (
+ <>
+
+
+ {intl.formatMessage({ id: 'ui-eholdings.tags' })}
+
+
+ {showClearButton && (
+ 0}
+ label={tagsFilterLabel}
+ onClick={handleClearButtonClick}
+ />
+ )}
+
+
+
+
+ >
+ );
+};
+
+TagsFilter.propTypes = propTypes;
+
+export { TagsFilter };
diff --git a/src/components/utilities.js b/src/components/utilities.js
index c29d7d683..ea5f0b203 100644
--- a/src/components/utilities.js
+++ b/src/components/utilities.js
@@ -295,3 +295,48 @@ export const handleSaveKeyFormSubmit = (formRef) => (event) => {
export const filterCountFromQuery = ({ q, sort, filter = [] }) => {
return [q, sort].concat(Object.values(filter)).filter(Boolean).length;
};
+
+export const getTagsList = (tags, dataOptions) => {
+ let tagsList = [];
+
+ if (tags && dataOptions.length) {
+ tagsList = Array.isArray(tags)
+ ? tags
+ : tags.split(',');
+ }
+
+ tagsList = tagsList
+ .filter(tag => dataOptions.some(option => option.value === tag))
+ .map(tag => tag.toLowerCase())
+ .sort();
+
+ return tagsList;
+};
+
+export const getAccessTypesList = (accessTypes) => {
+ let accessTypesList = [];
+
+ if (accessTypes) {
+ accessTypesList = Array.isArray(accessTypes)
+ ? accessTypes
+ : accessTypes.split(',');
+ }
+
+ accessTypesList.sort();
+
+ return accessTypesList;
+};
+
+export const normalize = (query = {}) => {
+ return {
+ filter: query.filter || {
+ tags: undefined,
+ type: undefined,
+ selected: undefined,
+ 'access-type': undefined,
+ },
+ q: query.q || '',
+ searchfield: query.searchfield,
+ sort: query.sort,
+ };
+};
diff --git a/src/routes/package-show-route/package-show-route.js b/src/routes/package-show-route/package-show-route.js
index f5599e2e4..441d4e6dd 100644
--- a/src/routes/package-show-route/package-show-route.js
+++ b/src/routes/package-show-route/package-show-route.js
@@ -19,7 +19,7 @@ import {
} from '../../constants';
import View from '../../components/package/show';
-import SearchModal from '../../components/search-modal';
+import { SearchSection } from '../../components/search-section';
class PackageShowRoute extends Component {
static propTypes = {
@@ -397,7 +397,6 @@ class PackageShowRoute extends Component {
const {
pkgSearchParams,
- queryId,
isTitlesUpdating,
} = this.state;
@@ -440,15 +439,13 @@ class PackageShowRoute extends Component {
history.location.state.isDestroyed
}
searchModal={
-
}
/>
diff --git a/src/routes/package-show-route/package-show-route.test.js b/src/routes/package-show-route/package-show-route.test.js
index 435d522e0..0fe98d39a 100644
--- a/src/routes/package-show-route/package-show-route.test.js
+++ b/src/routes/package-show-route/package-show-route.test.js
@@ -10,6 +10,8 @@ import {
waitFor,
} from '@folio/jest-config-stripes/testing-library/react';
+import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
+
import PackageShowRoute from './package-show-route';
import Harness from '../../../test/jest/helpers/harness';
@@ -510,9 +512,8 @@ describe('Given PackageShowRoute', () => {
});
describe('when package search params change', () => {
- it('should handle getPackageTitles', () => {
+ it('should handle getPackageTitles', async () => {
const {
- getAllByTestId,
getByRole,
} = renderPackageShowRoute({
getPackageTitles: mockGetPackageTitles,
@@ -525,11 +526,9 @@ describe('Given PackageShowRoute', () => {
},
});
- fireEvent.click(getAllByTestId('search-badge')[0]);
- fireEvent.change(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' }), {
- target: { value: 'Title name' },
- });
- fireEvent.click(getByRole('button', { name: 'ui-eholdings.label.search' }));
+ const searchBox = getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' });
+
+ await userEvent.type(searchBox, 'Title name{enter}');
expect(mockGetPackageTitles).toHaveBeenCalledWith({
packageId,
@@ -550,9 +549,8 @@ describe('Given PackageShowRoute', () => {
});
describe('when changed param is not single and it is not "page"', () => {
- it('should handle clearPackageTitles', () => {
+ it('should handle clearPackageTitles', async () => {
const {
- getAllByTestId,
getByRole,
} = renderPackageShowRoute({
clearPackageTitles: mockClearPackageTitles,
@@ -565,11 +563,9 @@ describe('Given PackageShowRoute', () => {
},
});
- fireEvent.click(getAllByTestId('search-badge')[0]);
- fireEvent.change(getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' }), {
- target: { value: 'Title name' },
- });
- fireEvent.click(getByRole('button', { name: 'ui-eholdings.label.search' }));
+ const searchBox = getByRole('searchbox', { name: 'ui-eholdings.search.enterYourSearch' });
+
+ await userEvent.type(searchBox, 'Title name{enter}');
expect(mockClearPackageTitles).toHaveBeenCalled();
});
@@ -694,7 +690,7 @@ describe('Given PackageShowRoute', () => {
describe('when remove package from holdings', () => {
describe('when model is not custom', () => {
it('should handle updatePackage', () => {
- const { getByRole } = renderPackageShowRoute({
+ const { getAllByRole, getByRole } = renderPackageShowRoute({
updatePackage: mockUpdatePackage,
model: {
...model,
@@ -702,7 +698,7 @@ describe('Given PackageShowRoute', () => {
},
});
- fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+ fireEvent.click(getAllByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' })[0]);
fireEvent.click(getByRole('button', { name: 'ui-eholdings.package.removeFromHoldings' }));
fireEvent.click(getByRole('button', { name: 'ui-eholdings.package.modal.buttonConfirm' }));
@@ -712,7 +708,7 @@ describe('Given PackageShowRoute', () => {
describe('when model is custom', () => {
it('should handle destroyPackage', () => {
- const { getByRole } = renderPackageShowRoute({
+ const { getByRole, getAllByRole } = renderPackageShowRoute({
destroyPackage: mockDestroyPackage,
model: {
...model,
@@ -721,7 +717,7 @@ describe('Given PackageShowRoute', () => {
},
});
- fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+ fireEvent.click(getAllByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' })[0]);
fireEvent.click(getByRole('button', { name: 'ui-eholdings.package.deletePackage' }));
fireEvent.click(getByRole('button', { name: 'ui-eholdings.package.modal.buttonConfirm.isCustom' }));
@@ -792,14 +788,14 @@ describe('Given PackageShowRoute', () => {
describe('when click on Edit button', () => {
it('should redirect to edit package page', () => {
- const { getByRole } = renderPackageShowRoute({
+ const { getByRole, getAllByRole } = renderPackageShowRoute({
model: {
...model,
isSelected: true,
},
});
- fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+ fireEvent.click(getAllByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' })[0]);
fireEvent.click(getByRole('button', { name: 'ui-eholdings.actionMenu.edit' }));
expect(historyReplaceSpy).toHaveBeenCalledWith({
diff --git a/translations/ui-eholdings/en.json b/translations/ui-eholdings/en.json
index 1b0220071..2a882f81a 100644
--- a/translations/ui-eholdings/en.json
+++ b/translations/ui-eholdings/en.json
@@ -635,5 +635,8 @@
"permission.settings.custom-labels.view": "Settings (eholdings): Can view custom labels",
"permission.settings.usage-consolidation.view": "Settings (eholdings): View Usage Consolidation API credentials",
"permission.settings.usage-consolidation.create-edit": "Settings (eholdings): Create, edit, and view Usage Consolidation API credentials",
- "permission.settings.assignedUser": "Settings (eHoldings): Can assign/unassign a user from a KB"
+ "permission.settings.assignedUser": "Settings (eHoldings): Can assign/unassign a user from a KB",
+
+ "actionMenu.label": "Actions",
+ "actionMenu.filterBadgeTooltip": "{count} applied {count, plural, one {filter} other {filters}}"
}