import { CreateManyParams, DeepPartial, DeleteManyParams, FiltersMap, KeyedItem, OptimisticActions, ToastConfig, UpdateAllParams, UpdateManyParams, } from '@wix/bex-core'; import { NestedTableNodeState } from './NestedTableNodeState'; import once from 'lodash/once'; import { getNodeOrLeaf } from './getNodeOrLeaf'; import { NestedTableNodeStatePublicAPI } from './NestedTableNodeStatePublicAPI'; import { action, makeObservable } from 'mobx'; export interface NestedDeleteManyParams extends DeleteManyParams {} export interface NestedUpdateManyParams extends UpdateManyParams { /** * Indicates whether to propagate the update to child nodes. */ propagate?: boolean; /** * Partial data to patch the items with. */ patch?: DeepPartial; } export interface NestedTableNodeStateOptimisticActionsPublicAPI extends OptimisticActions { /** * Updates multiple items * @param items - The items to update. * @param params - Additional parameters for the update operation. * @param params.propagate - Indicates whether to propagate the update children nodes * @param params.patch - Partial data to patch the items with. */ updateMany(items: T[], params: NestedUpdateManyParams): void; /** * Updates one item * @param item - The items to update. * @param params - Additional parameters for the update operation. * @param params.propagate - Indicates whether to propagate the update children nodes * @param params.patch - Partial data to patch the items with. */ updateOne(item: T, params: NestedUpdateManyParams): void; /** * Deletes multiple items and their descendants * @param items - An array of items to delete. * @param params - Additional parameters for the delete operation. */ deleteMany(items: T[], params: NestedDeleteManyParams): void; /** * Deletes one item and its descendants * @param item - An array of items to delete. * @param params - Additional parameters for the delete operation. */ deleteOne(item: T, params: NestedDeleteManyParams): void; } interface BaseActionParams { submit: (...args: any) => any; successToast?: ToastConfig | string; errorToast?: ( err: unknown, params: { retry: () => void }, ) => ToastConfig | string; } export class NestedTableNodeStateOptimisticActions< C extends string, T, F extends FiltersMap, > implements NestedTableNodeStateOptimisticActionsPublicAPI { readonly node; constructor(node: NestedTableNodeState) { this.node = node; makeObservable(this, { _propagate: action, _runAction: action, deleteMany: action, updateMany: action, }); } _getActionsParams(params: A) { const primaryActionParams = { ...params, submit: once(params.submit), }; const secondaryActionParams = { ...primaryActionParams, successToast: undefined, errorToast: undefined, }; return { primaryActionParams, secondaryActionParams, }; } _runAction( action: (optimisticActions: OptimisticActions, params: A) => void, params: A, ) { const { node: { flatModeCollection, children, nestedTable }, } = this; const { primaryActionParams, secondaryActionParams } = this._getActionsParams(params); if (children?._optimisticActions) { action(children._optimisticActions, primaryActionParams); } if (flatModeCollection?._optimisticActions) { action(flatModeCollection._optimisticActions, secondaryActionParams); } if ( nestedTable.toolbar.collection !== children && nestedTable.toolbar.collection._optimisticActions ) { action( nestedTable.toolbar.collection._optimisticActions, secondaryActionParams, ); } } _propagate( items: T[], action: ( nodes: NestedTableNodeStatePublicAPI, subItems: T[], ) => void, ) { const { node } = this; if (!node.children) { return; } const { itemKey, result: { _keyedItemsMap }, } = node.collection; const directItems = items.map((item) => _keyedItemsMap.get(itemKey(item)), ) as KeyedItem[]; const directNodes = directItems.map((keyedItem) => getNodeOrLeaf(node, keyedItem), ); for (const subNode of directNodes) { const subItems = subNode.children?.result.items as T[]; if (!subItems?.length) { continue; } action(subNode, subItems); } } createOne(item: T, params: CreateManyParams) { this.createMany([item], params); } createMany(items: T[], params: CreateManyParams) { this._runAction((a, p) => a.createMany(items, p), params); } updateAll(patchOrFn: (item: T) => Partial, params: UpdateAllParams) { this._runAction((a, p) => a.updateAll(patchOrFn, p), params); } deleteMany(items: T[], params: NestedDeleteManyParams) { const { primaryActionParams, secondaryActionParams } = this._getActionsParams(params); this._propagate(items, (subNode, subItems) => { subNode.optimisticActions?.deleteMany(subItems, secondaryActionParams); }); this._runAction((a, p) => a.deleteMany(items, p), primaryActionParams); } deleteOne(item: T, params: NestedDeleteManyParams) { this.deleteMany([item], params); } deleteAll(params: UpdateAllParams) { this._runAction((a, p) => a.deleteAll(p), params); } updateMany(items: T[], params: NestedUpdateManyParams) { const { primaryActionParams, secondaryActionParams } = this._getActionsParams(params); if (params?.propagate) { this._propagate(items, (subNode, subItems) => { subNode.optimisticActions?.updateMany(subItems, secondaryActionParams); }); } this._runAction((a, p) => a.updateMany(items, p), primaryActionParams); } updateOne(item: T, params: NestedUpdateManyParams) { this.updateMany([item], params); } }