import { wordStartsWithMatch } from '../utils/wordStartsWithMatch'; import { BasicCategory, PrivateView } from '../model'; import { getCategoryName, getViewName, } from '../components/CollectionViewsDropdown/viewsDropdownRenderHelpers'; import { action, computed, makeObservable, observable } from 'mobx'; import { ViewsState } from './ViewsState'; import { FiltersMap } from '@wix/bex-core'; import { ViewsLocalSearchBIReporter } from './ViewsLocalSearchBIReporter'; type CategoryWithViews = BasicCategory & { views: PrivateView[]; }; export interface ViewsLocalSearchStateParams { readonly views: ViewsState; } export class ViewsLocalSearchState { readonly views; readonly bi; readonly scheduleLocalSearch; get container() { return this.views.container; } get collection() { return this.views.collection; } inputValue = ''; // collection.query.search is for server side search - so we use this simple variable for local search localSearchValue = ''; setInputValueAndScheduleSearch = action((value: string) => { this.inputValue = value; this.scheduleLocalSearch(); }); clearSearch = action(() => { this.inputValue = ''; this._setLocalSearchValue(); }); _setLocalSearchValue = action((value = this.inputValue) => { this.localSearchValue = value; }); _search = action(() => { this._setLocalSearchValue(); this.bi.onSearch(); }); constructor(params: ViewsLocalSearchStateParams) { this.views = params.views; this.scheduleLocalSearch = this.container.lodash.debounce( this._search, 300, ); this.bi = new ViewsLocalSearchBIReporter({ state: this }); makeObservable(this, { inputValue: observable.ref, localSearchValue: observable.ref, categoriesWithViews: computed, filteredCategoriesWithViews: computed, }); } init() { return this.bi.init(); } get filteredCategoriesWithViews() { const { localSearchValue, categoriesWithViews } = this; const { viewsWithoutCategory, categories } = categoriesWithViews; const q = localSearchValue.trim(); if (!q.length) { return { viewsWithoutCategory, categories, }; } const startsWith = wordStartsWithMatch(q); const viewPredicate = (view: PrivateView) => startsWith(getViewName({ view, viewsState: this.views })); const transformCategory = (category: CategoryWithViews) => { if (startsWith(getCategoryName({ category, viewsState: this.views }))) { return category; } return { ...category, views: category.views.filter(viewPredicate), }; }; return { viewsWithoutCategory: viewsWithoutCategory.filter(viewPredicate), categories: categories .map(transformCategory) .filter((c) => c.views.length), }; } get categoriesWithViews() { const { collection: { result: { items }, }, views: { basicCategories }, } = this; const viewsWithoutCategory = [] as PrivateView[]; const categoriesMap = new Map>([]); for (const view of items) { if (!view.categoryId) { viewsWithoutCategory.push(view); } else { let category = categoriesMap.get(view.categoryId); if (!category) { category = { ...basicCategories[view.categoryId], views: [], }; categoriesMap.set(view.categoryId, category); } category.views.push(view); } } return { categories: Array.from(categoriesMap.values()), viewsWithoutCategory, }; } }