diff --git a/src/constants/filters.ts b/src/constants/filters.ts index 99ad5baad0..b74c371e62 100644 --- a/src/constants/filters.ts +++ b/src/constants/filters.ts @@ -88,7 +88,7 @@ const filterCodesPerCategory = deepFreeze>({ * } *``` */ -const initFilters = () => +export const initFilters = () => Object.entries(filterCodesPerCategory).reduce( (acc, [filterType, filters]) => ({ ...acc, diff --git a/src/stores/search.ts b/src/stores/search.ts index c9335f2818..2d77997d48 100644 --- a/src/stores/search.ts +++ b/src/stores/search.ts @@ -158,28 +158,15 @@ export const useSearchStore = defineStore('search', () => { } /** - * Replaces filters with the newFilterData parameter, making sure that - * audio/image provider filters are handled correctly. + * Replaces filters with the newFilterData object that was created using initial filters, + * and setting parameters from the search query to checked. + * + * + * */ function replaceFilters(newFilterData: Filters) { - const providerFilters: FilterCategory[] = [ - 'audioProviders', - 'imageProviders', - ] - allFilterCategories.forEach((filterCategory) => { - if (providerFilters.includes(filterCategory)) { - newFilterData[filterCategory].forEach((provider) => { - const idx = state.filters[filterCategory].findIndex( - (p) => p.code === provider.code - ) - if (idx > -1) { - state.filters[filterCategory][idx].checked = provider.checked - } - }) - } else { - state.filters[filterCategory] = newFilterData[filterCategory] - } + state.filters[filterCategory] = newFilterData[filterCategory] }) } @@ -281,10 +268,8 @@ export const useSearchStore = defineStore('search', () => { if (item.code.includes('nd')) { dependentFilters.push('modification') } - return ( - state.filters.licenseTypes.some( - (item) => dependentFilters.includes(item.code) && item.checked - ) + return state.filters.licenseTypes.some( + (item) => dependentFilters.includes(item.code) && item.checked ) } } diff --git a/src/utils/get-legacy-source-url.js b/src/utils/get-legacy-source-url.js index 658105eeec..3a5f55c2e6 100644 --- a/src/utils/get-legacy-source-url.js +++ b/src/utils/get-legacy-source-url.js @@ -40,6 +40,7 @@ export const legacySourceMap = { Europeana: { audio(search) { let query = `${search.q} AND RIGHTS:*creative*` // search cc licensed works + if (search.filters && search.filters.commercial) { if (search.filters.commercial) query = `${query} AND NOT RIGHTS:*nc*` if (search.filters.modify) query = `${query} AND NOT RIGHTS:*nd*` diff --git a/src/utils/search-query-transform.ts b/src/utils/search-query-transform.ts index 4bb0f6a201..9b98cc5f86 100644 --- a/src/utils/search-query-transform.ts +++ b/src/utils/search-query-transform.ts @@ -104,6 +104,7 @@ export const queryStringToSearchType = ( * `source` - audioProviders/imageProviders * `extensions` - audioExtensions/imageExtensions * `categories` - audioCategories/imageCategories + * * This function sets only filters that are possible for current * media type. E.g., for queryString `search/audio?extensions=ogg` * the `audioExtensions.ogg.checked` is set to true, @@ -132,7 +133,13 @@ const getMediaTypeApiFilters = ( } /** - * Converts the browser filter query string into the internal filter store data format + * Converts the browser filter query string into the internal filter store data format. + * For the API parameters that have the same name, but correspond to different filter categories + * (`differentFiltersWithSameApiParams`), only the filters that exist for the selected search type + * are used: + * E.g. when the search type is `audio`, `extension=jpg,mp3` sets the audioExtensions mp3.checked to true, + * and discards `jpg`. + * * @param query - browser filter query * @param searchType - search type determines which filters are applied * @param defaultFilters - default filters for testing purposes @@ -160,23 +167,29 @@ export const queryToFilterData = ({ ] filterTypes.forEach((filterDataKey) => { if (differentFiltersWithSameApiParams.includes(filterDataKey)) { - const parameter = query[filterPropertyMappings[filterDataKey]] - if (parameter) { - filters[filterDataKey] = getMediaTypeApiFilters( - parameter, - filters[filterDataKey] - ) + if (filterDataKey.startsWith(searchType)) { + const parameter = query[filterPropertyMappings[filterDataKey]] + if (parameter) { + filters[filterDataKey] = getMediaTypeApiFilters( + parameter, + filters[filterDataKey] + ) + } } } else { const queryDataKey = filterPropertyMappings[filterDataKey] if (query[queryDataKey]) { - const filterValues = query[queryDataKey].split(',') - filterValues.forEach((val: string) => { - const idx = filters[filterDataKey].findIndex((f) => f.code === val) - if (idx >= 0) { - filters[filterDataKey][idx].checked = true - } - }) + if (queryDataKey === 'mature' && query[queryDataKey].length > 0) { + filters[filterDataKey][0].checked = true + } else { + const filterValues = query[queryDataKey].split(',') + filterValues.forEach((val: string) => { + const idx = filters[filterDataKey].findIndex((f) => f.code === val) + if (idx >= 0) { + filters[filterDataKey][idx].checked = true + } + }) + } } } }) diff --git a/test/unit/specs/stores/search-store.spec.js b/test/unit/specs/stores/search-store.spec.js index 35944587dd..6ccfc5b1ac 100644 --- a/test/unit/specs/stores/search-store.spec.js +++ b/test/unit/specs/stores/search-store.spec.js @@ -10,14 +10,9 @@ import { supportedSearchTypes, VIDEO, } from '~/constants/media' -import { warn } from '~/utils/console.ts' import { useSearchStore } from '~/stores/search' -jest.mock('~/utils/console', () => ({ - warn: jest.fn(), -})) - describe('Search Store', () => { beforeEach(() => { setActivePinia(createPinia()) @@ -375,10 +370,12 @@ describe('Search Store', () => { const searchStore = useSearchStore() const expectedFilters = searchStore.filters - searchStore.toggleFilter({ filterType: 'licenses' }) - expect(warn).toHaveBeenCalledWith( + expect(() => + searchStore.toggleFilter({ filterType: 'licenses' }) + ).toThrow( 'Cannot toggle filter of type licenses. Use code or codeIdx parameter' ) + expect(searchStore.filters).toEqual(expectedFilters) }) diff --git a/test/unit/specs/utils/search-query-transform.spec.js b/test/unit/specs/utils/search-query-transform.spec.js index d8cbcfbff8..4154ae3af9 100644 --- a/test/unit/specs/utils/search-query-transform.spec.js +++ b/test/unit/specs/utils/search-query-transform.spec.js @@ -7,7 +7,7 @@ import { } from '~/utils/search-query-transform' import { AUDIO, IMAGE } from '~/constants/media' -import { filterData } from '~/constants/filters.ts' +import { filterData, initFilters } from '~/constants/filters.ts' describe('searchQueryTransform', () => { it('converts initial filters to query data', () => { @@ -270,6 +270,58 @@ describe('searchQueryTransform', () => { }) expect(result).toEqual(filters) // toEqual checks for value equality }) + + it('queryToFilterData discards all image filters when search type is audio', () => { + const filters = initFilters() + filters.audioProviders = [ + { code: 'jamendo', checked: false }, + { code: 'wikimedia_audio', checked: false }, + ] + /** + * `categories` and `extension` parameter values will not be used because those + * codes (`photograph` and `svg`) only exist for the `imageCategories` and `imageExtensions` + * filter categories. + * `source` will only use the `wikimedia_audio` and `jamendo` parameters because they + * exist in `filters.audioProviders` list before. Other values either exist in + * `filters.imageProviders` list, or do not exist at all, so they are discarded. + * Valid filter items for categories that exist for all search types + * (`license`, `license_type`, `searchBy`, `mature`) are set to checked. + * Invalid filter items for valid categories (`nonexistent` in `license`) + * are discarded. + */ + const query = { + q: 'cat', + license: 'cc0,nonexistent', + license_type: 'commercial', + categories: 'photograph', + extension: 'svg', + duration: 'medium', + source: 'animaldiversity,wikimedia,nonexistent,wikimedia_audio,jamendo', + searchBy: 'creator', + mature: 'true', + } + const expectedFilters = clonedeep(filters) + const setChecked = (code, filterCategory) => { + const idx = expectedFilters[filterCategory].findIndex( + (item) => item.code === code + ) + expectedFilters[filterCategory][idx].checked = true + } + setChecked('cc0', 'licenses') + setChecked('commercial', 'licenseTypes') + setChecked('medium', 'durations') + setChecked('creator', 'searchBy') + setChecked('mature', 'mature') + setChecked('jamendo', 'audioProviders') + setChecked('wikimedia_audio', 'audioProviders') + + const result = queryToFilterData({ + query, + searchType: AUDIO, + defaultFilters: filters, + }) + expect(result).toEqual(expectedFilters) // toEqual checks for value equality + }) it('queryStringToQueryData', () => { const expectedQueryData = { license: 'cc0',