Ctrl K
ComunidadGuías…

src/lib/pipeline-fields.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * Which optional fields each pipeline view draws.
 *
 * Pure, so the board, the table, the calendar, the menu that toggles them and
 * the tool that reads them all agree on one catalogue.
 *
 * On the board and the table, three things are never in a catalogue: the
 * company, the role title and the stage. Those are what a card IS — a card
 * with no company is not a shorter card, it is an unreadable one — and on the
 * table the stage cell is the inline editor the table exists for. A setting
 * that can make a screen useless is not a setting.
 *
 * The calendar is the exception, and only for stage: a chip is one line of an
 * entry's own title, so the stage is genuinely extra there rather than
 * identity, and it is off by default.
 *
 * An empty stored list means "the default set", not "draw nothing". That way an
 * account that has never touched this looks exactly as it always did, and a
 * field added here later appears for everybody rather than hiding behind a
 * stored list that predates it. Turning everything off is expressed as the
 * sentinel below, because an empty array already means something else.
 */

export const PIPELINE_VIEWS = ["board", "list", "calendar"] as const;
export type PipelineView = (typeof PIPELINE_VIEWS)[number];

/** "I mean none of them", as distinct from "I have never said". */
export const NO_FIELDS = "none";

export type FieldDef = {
  key: string;
  label: string;
  /** In the default set. */
  standard: boolean;
  /** Only drawn once the viewport is wide enough, whatever this says. */
  wide?: boolean;
};

export const BOARD_FIELDS: FieldDef[] = [
  { key: "location", label: "Location", standard: true },
  { key: "salary", label: "Salary", standard: true },
  { key: "followUp", label: "Next follow-up", standard: true },
  { key: "quiet", label: "Quiet for", standard: true },
  { key: "resume", label: "Resume sent", standard: true },
  { key: "activity", label: "Activity count", standard: true },
  { key: "tags", label: "Tags", standard: false },
];

export const LIST_FIELDS: FieldDef[] = [
  { key: "followUp", label: "Follow-up", standard: true },
  { key: "waiting", label: "Waiting", standard: true },
  { key: "quiet", label: "Quiet", standard: true, wide: true },
  { key: "salary", label: "Salary", standard: true, wide: true },
  { key: "location", label: "Location", standard: true, wide: true },
  { key: "activity", label: "Log", standard: true, wide: true },
  { key: "updated", label: "Touched", standard: true, wide: true },
];

/**
 * The calendar draws a chip, and a chip has room for very little.
 *
 * Only two things on a schedule entry are not already inside its own title —
 * everything else would print the same words twice.
 */
export const CALENDAR_FIELDS: FieldDef[] = [
  // Both are wide-screen only: a chip in a month grid has no room for either
  // below `lg`, and a toggle that appears to do nothing is worse than one that
  // says when it applies.
  { key: "detail", label: "The role or the detail", standard: true, wide: true },
  { key: "stage", label: "Stage", standard: false, wide: true },
];

export const FIELDS: Record<PipelineView, FieldDef[]> = {
  board: BOARD_FIELDS,
  list: LIST_FIELDS,
  calendar: CALENDAR_FIELDS,
};

export const VIEW_LABEL: Record<PipelineView, string> = {
  board: "Board",
  list: "Table",
  calendar: "Calendar",
};

export function isPipelineView(value: string): value is PipelineView {
  return (PIPELINE_VIEWS as readonly string[]).includes(value);
}

/**
 * What a view actually draws, given what is stored.
 *
 * Unknown keys are dropped rather than honoured, so a field removed from a
 * catalogue does not linger in somebody's saved list forever.
 */
export function visibleFields(view: PipelineView, stored: string[]): Set<string> {
  const catalogue = FIELDS[view];
  if (stored.length === 0) {
    return new Set(catalogue.filter((field) => field.standard).map((field) => field.key));
  }
  if (stored.length === 1 && stored[0] === NO_FIELDS) return new Set();
  const known = new Set(catalogue.map((field) => field.key));
  return new Set(stored.filter((key) => known.has(key)));
}

/** The stored form of a chosen set, collapsing "nothing" to the sentinel. */
export function storedFields(view: PipelineView, chosen: Set<string>): string[] {
  if (chosen.size === 0) return [NO_FIELDS];
  const catalogue = FIELDS[view];
  const ordered = catalogue.filter((field) => chosen.has(field.key)).map((field) => field.key);
  // A set that happens to equal the default is still written out, because the
  // person said it. Only "I never chose" is the empty array.
  return ordered;
}