import { reaction } from 'mobx'; import { History, replaceSearchParamsWith } from '@wix/bex-core'; import { CustomColumnsState } from './CustomColumnsState'; import { ViewType } from '../model'; function parseSelectedColumnsString(selectedColumnsFromUrl: string) { return selectedColumnsFromUrl .split(',') .map((columnExpression) => { const [id = '', isSelected] = columnExpression.split(' '); return { id: decodeURIComponent(id), isSelected: isSelected !== 'false', }; }) .filter(({ id }) => id); } // Legacy `selectedColumns` stays bound to non-spreadsheet layouts so existing // deep links keep their meaning; spreadsheet uses a sibling param. const SELECTED_COLUMNS_PARAM = 'selectedColumns'; const SPREADSHEET_SELECTED_COLUMNS_PARAM = 'spreadsheetSelectedColumns'; const getSelectedColumnsParamForLayout = ( layout: ViewType | undefined, ): string => layout === 'spreadsheet' ? SPREADSHEET_SELECTED_COLUMNS_PARAM : SELECTED_COLUMNS_PARAM; const serializeSelectedColumns = ( selectedColumns: readonly { id: string; isSelected?: boolean; }[], ) => selectedColumns .map( (c) => `${encodeURIComponent(c.id)}${!c.isSelected ? ' false' : ''}`, ) .join(','); export interface CustomColumnsHistoryStateParams { customColumns: CustomColumnsState; history: History; } export class CustomColumnsHistoryState { readonly customColumns; readonly history; get selectedColumnsSearchParamName(): string { return getSelectedColumnsParamForLayout( this.customColumns.table.layoutState?.viewType, ); } // Live, per-layout read — unlike `_selectedColumnsFromUrl` (frozen at the // initial layout), this reflects the active layout after a switch so URL // takes precedence over dataCapsule per layout, not just on first load. get hasUrlColumnsForCurrentLayout(): boolean { const params = new URLSearchParams(this.history.location.search); return !!params.get(this.selectedColumnsSearchParamName); } _selectedColumnsFromUrl?: string | null; constructor(params: CustomColumnsHistoryStateParams) { this.customColumns = params.customColumns; this.history = params.history; this._preInitHistoryPersistence(); } _preInitHistoryPersistence() { const { history, customColumns } = this; const searchParams = new URLSearchParams(history.location.search); this._selectedColumnsFromUrl = searchParams.get( this.selectedColumnsSearchParamName, ); if (this._selectedColumnsFromUrl) { this.customColumns.table.selectedColumns.setValue( parseSelectedColumnsString(this._selectedColumnsFromUrl), ); customColumns.table.multi.collections.forEach(({ query }) => { query._initializedFromHistory = true; }); } } init() { const disposers = [ reaction( () => this.customColumns.table.selectedColumns.value, (selectedColumns) => { const paramName = this.selectedColumnsSearchParamName; replaceSearchParamsWith(this.history, (searchParams) => { if (selectedColumns.length) { searchParams.set( paramName, serializeSelectedColumns(selectedColumns), ); } else { searchParams.delete(paramName); } }); }, { fireImmediately: true, delay: 250, }, ), reaction( () => this.customColumns.table.layoutState?.viewType, (newLayout, prevLayout) => { if (!newLayout || !prevLayout || newLayout === prevLayout) { return; } if (this.customColumns.table._cacheRestoredLayout === newLayout) { return; } // Views path is handled by CollectionViewsState's own reaction. if (this.customColumns.table.viewsProps) { return; } const searchParams = new URLSearchParams( this.history.location.search, ); const value = searchParams.get( getSelectedColumnsParamForLayout(newLayout), ); if (value) { this.customColumns.table.selectedColumns.setValue( parseSelectedColumnsString(value), ); } else { this.customColumns.table.selectedColumns.reset(); } }, ), ]; return () => { disposers.forEach((d) => d()); }; } }