import { FiltersMap, WixPatternsContainer, DataResultRaw, CollectionState, CollectionStateParams, stringFilter, CollectionOptimisticActions, QueryState, } from '@wix/bex-core'; import { action, computed, makeObservable, observable, runInAction, } from 'mobx'; export interface KanbanStageStateBaseParams { readonly container: WixPatternsContainer; readonly initialPage?: DataResultRaw; readonly name: string; readonly key: string; readonly kanbanId: string; } export interface KanbanStageStateParams< T, S, F extends FiltersMap & { stageId: ReturnType }, > extends KanbanStageStateBaseParams { readonly fetchData: CollectionStateParams['fetchData']; readonly itemKey: CollectionStateParams['itemKey']; readonly itemName: CollectionStateParams['itemName']; readonly stage: S; readonly query: QueryState; } export class KanbanStageState< T, S, F extends FiltersMap & { stageId: ReturnType }, > { readonly container: WixPatternsContainer; readonly itemsCollectionState: CollectionState; name: string; readonly key: string; readonly kanbanId: string; readonly stage: S; _total?: number; isRefetching = false; private optimisticActions: CollectionOptimisticActions; constructor(params: KanbanStageStateParams) { this.container = params.container; this.name = params.name; this.key = params.key; this.kanbanId = params.kanbanId; this.stage = params.stage; this._total = params.initialPage?.total ?? undefined; this.itemsCollectionState = new CollectionState({ errorMonitor: this.container.errorMonitor, history: this.container.history, lodash: this.container.lodash, onlineState: this.container.onlineState, queryCache: this.container.queryCache, translate: this.container.translate, queryName: `kanban-items-${this.kanbanId}-${this.key}`, fetchData: params.fetchData, itemKey: params.itemKey, itemName: params.itemName, filters: { ...params.query.filters, stageId: stringFilter({ initialValue: this.key }), }, initialPage: params.initialPage, errorHandler: this.container.errorHandler, paginationMode: 'cursor', search: params.query.search, }); this.optimisticActions = new CollectionOptimisticActions({ collection: this.itemsCollectionState, container: this.container, }); makeObservable(this, { name: observable, _total: observable, fetchMore: action, stageName: computed, stageKey: computed, isRefetching: observable, hasError: computed, setTotal: action, isLoading: computed, totalItems: computed, }); } init() { const disposers = [ this.itemsCollectionState.init({ skipFilterListeners: true }), this.optimisticActions.init(), ]; return () => { disposers.forEach((disposer) => disposer?.()); }; } get hasError() { return this.itemsCollectionState.result.status?.isError; } items() { return this.itemsCollectionState.keyedItems.map((item: any) => item.item); } itemName(item: T) { return this.itemsCollectionState.itemName(item); } itemKey(item: T) { return this.itemsCollectionState.itemKey(item); } get totalItems() { return this._total; } setTotal(total: number) { this._total = total; } get stageName() { return this.name; } get stageKey() { return this.key; } get isLoading() { return this.itemsCollectionState.initTask.status.isLoading; } fetchMore() { this.itemsCollectionState.fetchNextPageIfNeeded(); } isFetchingMore() { return true; } deleteItem(item: T) { this.itemsCollectionState.optimisticActions.deleteOne(item, { submit: () => Promise.resolve(), }); runInAction(() => { this.setTotal((this._total ?? 0) - 1); }); } createItem(item: T) { this.itemsCollectionState.optimisticActions.createOne(item, { submit: () => Promise.resolve(), }); runInAction(() => { this.setTotal((this._total ?? 0) + 1); }); } showErrorToast(error: unknown) { const resolvedError = this.container.errorHandler?.getResolvedError?.(error); resolvedError && this.container.errorHandler?.showError?.(resolvedError); } updateItem(updatedItem: T) { const allItems = this.itemsCollectionState.result.keyedItems.map( (k) => k.item, ); const updatedItems = allItems.map((item) => this.itemKey(item) === this.itemKey(updatedItem) ? updatedItem : item, ); this.itemsCollectionState.optimisticActions.updateMany(updatedItems, { submit: () => Promise.resolve(updatedItems), keepPosition: true, }); } async refetchStage() { runInAction(() => { this.isRefetching = true; }); try { await this.itemsCollectionState.refreshAllPages(); } finally { runInAction(() => { this.isRefetching = false; }); } } }