import { Filter, FilterOperator, OperatorFilterValue, operatorNeedsValue as coreOperatorNeedsValue, } from '@wix/bex-core'; import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { FilterToolbarState } from '../providers'; import { debounce } from 'lodash'; export interface OperatorFilterPickerStateParams { toolbar: FilterToolbarState; filter: Filter>; /** * Debounce delay in milliseconds before applying filter changes * @default 300 */ debounceMs?: number; } export class OperatorFilterPickerState { readonly toolbar: FilterToolbarState; readonly _filter: OperatorFilterPickerStateParams['filter']; private readonly debouncedRefresh: () => void; operator: FilterOperator; value: T | null; get filter() { return this.toolbar.getPendingFilter(this._filter); } constructor(params: OperatorFilterPickerStateParams) { this.toolbar = params.toolbar; this._filter = params.filter; this.operator = params.filter.value?.operator!; this.value = params.filter.value?.value ?? null; const debounceMs = params.debounceMs ?? 300; this.debouncedRefresh = debounce( () => this.refreshIfChanged({ actionType: 'add' }), debounceMs, ); makeObservable(this, { operator: observable, value: observable, isEmpty: computed, init: action, setOperator: action, setValue: action, onChange: action, applyImmediately: action, }); } get isEmpty() { return this.filter.isEmpty; } get currentValue(): OperatorFilterValue { return { operator: this.operator, value: this.value, }; } init() { const dispose = reaction( () => this.filter.value, (filterValue) => { this.operator = filterValue.operator; this.value = filterValue.value; }, { fireImmediately: true }, ); return () => { dispose(); }; } remove() { this.refreshIfChanged({ actionType: 'remove' }); } setOperator(operator: FilterOperator) { this.operator = operator; if (!this.operatorNeedsValue()) { this.value = null; } this.applyImmediately(); } setValue(value: T | null) { this.value = value; this.onChange(); } /** * Called when value changes - debounced */ onChange() { this.debouncedRefresh(); } /** * Apply filter changes immediately (used for operator changes) */ applyImmediately() { this.refreshIfChanged({ actionType: 'add' }); } private refreshIfChanged( options: { actionType?: 'add' | 'remove'; clickedValueKey?: string } = {}, ) { const newValue = this.currentValue; if (this.filter.hasDiff(newValue)) { this.filter.setValue(newValue, { emitEvents: ['change', 'beforeRefresh', 'refresh'], ...options, }); return true; } return false; } /** * Check if the given operator requires a value input */ operatorNeedsValue(): boolean { return coreOperatorNeedsValue(this.operator); } }