sort-priority.ts1.9 KBView on GitHub
/**
 * Sort-priority helpers.
 *
 * Sorting a canvas/table is multi-column: every active sort carries a `priority`
 * where 0 wins ties first. Activating a sort from a column header (or a column
 * popover) means "sort by this now", so the new sort takes priority 0 and every
 * other active sort shifts down one slot — it never lands silently at the bottom
 * of the list where it has no visible effect.
 *
 * Pure functions so both the canvas viewConfig writer and the CRMSlice reducer
 * can share the same rule.
 */

import type { ColumnSort } from '../store/crmSlice';

/** Anything keyed by column id that carries an optional sort — canvas config or CRM columns. */
type SortCarrier = { sort?: ColumnSort };

/**
 * Return a copy of `config` where `columnId` sorts at priority 0 and all other
 * active sorts are pushed down one slot (relative order preserved).
 */
export function withTopPrioritySort<T extends SortCarrier>(
  config: Record<string, T>,
  columnId: string,
  sort: Omit<ColumnSort, 'priority'>,
): Record<string, T> {
  const next: Record<string, T> = {};
  for (const [id, entry] of Object.entries(config)) {
    next[id] =
      id !== columnId && entry.sort?.active
        ? { ...entry, sort: { ...entry.sort, priority: entry.sort.priority + 1 } }
        : entry;
  }
  next[columnId] = { ...(next[columnId] ?? ({} as T)), sort: { ...sort, priority: 0 } };
  return next;
}

/**
 * Renumber active sorts to 0..n-1 following `orderedColumnIds`. Columns absent
 * from the list keep whatever they have (inactive sorts carry no priority).
 */
export function withSortOrder<T extends SortCarrier>(
  config: Record<string, T>,
  orderedColumnIds: string[],
): Record<string, T> {
  const next = { ...config };
  orderedColumnIds.forEach((id, index) => {
    const sort = next[id]?.sort;
    if (sort?.active) next[id] = { ...next[id], sort: { ...sort, priority: index } };
  });
  return next;
}