UNPKG

@empathyco/x-components

Version:
247 lines (244 loc) • 8.63 kB
import { isFacetFilter, isHierarchicalFacet } from '@empathyco/x-types'; import '@vue/devtools-api'; import '../../../plugins/devtools/timeline.devtools.js'; import '@empathyco/x-utils'; import 'rxjs/operators'; import 'rxjs'; import '../../../plugins/devtools/colors.utils.js'; import '../../../plugins/x-bus.js'; import { XPlugin } from '../../../plugins/x-plugin.js'; import { isArrayEmpty, arrayToObject, groupItemsBy } from '../../../utils/array.js'; import '../../../utils/storage.js'; import { FilterEntityFactory } from '../entities/filter-entity.factory.js'; import { flatHierarchicalFilters } from '../utils.js'; /** * Default implementation for the {@link FacetsService}. * * @public */ class DefaultFacetsService { constructor(filterEntityFactory = FilterEntityFactory.instance) { this.filterEntityFactory = filterEntityFactory; } /** * The {@link https://vuex.vuejs.org/ | Vuex} store to use in the service. * * @returns The store. * @internal */ get store() { return XPlugin.store; } setFacets(facetsGroup) { const newFilters = this.updateStore(facetsGroup); /* Ensures that filters are selected with valid values. For example, you can't set a single select facet with 2 or more selected filters */ this.updateFiltersSelectedState(newFilters); } updateFacets(facetsGroup) { const selectedFilters = this.getSelectedFilters(); const newFilters = this.updateStore(facetsGroup); this.updateFiltersSelectedState(newFilters, selectedFilters); } updatePreselectedFilters(filters) { this.setPreselectedFilter(filters); } selectPreselectedFilters() { this.select(this.store.state.x.facets.preselectedFilters); } clearFilters(facetIds, metadata) { this.getSelectedFilters() .filter(filter => !facetIds || (isFacetFilter(filter) && facetIds.includes(filter.facetId))) .forEach(filter => this.deselect.bind(this)(filter, metadata)); } clearFiltersWithMetadata({ facetIds, metadata, } = {}) { this.clearFilters(facetIds, metadata); } deselect(filter, metadata) { this.getFilterEntity(filter).deselect(filter, metadata); } select(filterOrFilters) { const filters = Array.isArray(filterOrFilters) ? filterOrFilters : [filterOrFilters]; filters.forEach(filter => this.getFilterEntity(filter).select(filter)); } toggle(filter) { if (filter.selected) { this.deselect(filter); } else { this.select(filter); } } /** * Sets the query. * * @param query - The query searched. * @internal */ setQuery(query) { this.store.commit('x/facets/setQuery', query); } /** * Creates an entity from a filter DTO. * * @param filter - The filter to create an entity from. * @returns The filter entity. * @internal */ getFilterEntity(filter) { return this.filterEntityFactory.getFilterEntity(this.store, filter); } /** * Sets in the store the Facets, the Filters and the FacetsGroup, without applying any logic * to the selected state. * * @param facetsGroup - The {@link FacetsGroup} to set into the store state. * @returns An array with the new filters. * @internal */ updateStore(facetsGroup) { this.removeGroupFacets(facetsGroup.id); this.removeGroupFilters(facetsGroup.id); facetsGroup.facets.forEach(facet => { this.setFacetGroup({ facetId: facet.id, groupId: facetsGroup.id }); this.setFacet(facet); }); const newFilters = this.flatFilters(facetsGroup); this.setFilters(newFilters); return newFilters; } /** * This function returns the filters of the facets group flattened in an array. It keeps the * relations between the filters (parent--children). * * @privateRemarks If it is necessary to deal with more cases than the hierarchical, we need to * refactor this logic and maybe move it to the entities, to not make this service dependant of * the facet type. At the moment it is only one `if`, and is ok as long as no more `if`s are * needed. * @param facetsGroup - The facets group from where extract the filters to flat. * @returns An array with the filters flattened. * @internal */ flatFilters(facetsGroup) { return facetsGroup.facets.flatMap(facet => isHierarchicalFacet(facet) ? flatHierarchicalFilters(facet.filters) : facet.filters); } /** * Retrieves the selected filters from the store. * * @returns The list of selected filters of the store. * @internal */ getSelectedFilters() { // eslint-disable-next-line ts/no-unsafe-member-access,ts/no-unsafe-return return this.store.getters['x/facets/selectedFilters']; } /** * Changes the filters selection state to match the store. * * @param newFilters - The list of filters to save. * @param previousFilters - (Optional) The list of old filters, used to set the `newFilters` * selected state. */ updateFiltersSelectedState(newFilters, previousFilters) { if (!isArrayEmpty(newFilters)) { const newStateFiltersMap = arrayToObject(previousFilters ?? newFilters, 'id'); newFilters.forEach(filter => { const filterEntity = this.getFilterEntity(filter); if (newStateFiltersMap[filter.id]?.selected) { filterEntity.select(filter); } else { filterEntity.deselect(filter); } }); } } /** * Removes the filters that belong to the given group. * * @param groupId - The id of the group from whom remove the filters that are in the store. * * @returns The removed filters. * * @internal */ removeGroupFilters(groupId) { const filtersToRemove = groupItemsBy(Object.values(this.store.state.x.facets.filters), filter => isFacetFilter(filter) ? this.store.state.x.facets.groups[filter.facetId] : '__unknown-group__')[groupId] ?? []; this.removeFilters(filtersToRemove); return filtersToRemove; } /** * Removes the facets that belong to the given group. * * @param groupId - The id of the group from whom remove the facets that are in the store. * @returns The removed facets. * @internal */ removeGroupFacets(groupId) { const facetsToRemove = Object.values(this.store.state.x.facets.facets).filter(facet => this.store.state.x.facets.groups[facet.id] === groupId); facetsToRemove.forEach(this.removeFacet.bind(this)); return facetsToRemove; } /** * Sets the group that a facet belongs to. * * @param facetGroup - The id of the facet, and the group it belongs to. * @internal */ setFacetGroup(facetGroup) { this.store.commit('x/facets/setFacetGroup', facetGroup); } /** * Sets the Facet to the store facets record. * * @param facet - The facet to store. * @internal */ setFacet({ filters, ...restFacet }) { this.store.commit('x/facets/setFacet', restFacet); } /** * Removes a facet from the store. * * @param facet - The facet to remove. * @internal */ removeFacet(facet) { this.store.commit('x/facets/removeFacet', facet); } /** * Saves a list of filters to the store without any state change logic applied. * * @param filters - The filters to save. * @internal */ setFilters(filters) { this.store.commit('x/facets/setFilters', filters); } /** * Saves a list of preselected filters to the store without any state change logic applied. * * @param filters - The filters to save. * @internal */ setPreselectedFilter(filters) { this.store.commit('x/facets/setPreselectedFilters', filters); } /** * Removes a list of filters from the store. * * @param filters - The filters to remove. * @internal */ removeFilters(filters) { this.store.commit('x/facets/removeFilters', filters); } } /** * Global instance of the {@link FacetsService}. */ DefaultFacetsService.instance = new DefaultFacetsService(); export { DefaultFacetsService }; //# sourceMappingURL=facets.service.js.map