@empathyco/x-components
Version:
Empathy X Components
247 lines (244 loc) • 8.63 kB
JavaScript
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