# SalesWorkspaceMap

> A read-only React Flow map of how a workspace's lists, signals, campaigns, rules and pipelines connect.

## Facts

- **Product**: Max
- **Family**: Pipeline
- **Global**: `window.DigitalCrew.SalesWorkspaceMap`
- **Source**: `max-agent: src/features/sales-workspace/ui/sales-workspace-map.tsx`
- **Import in the app**: `import { SalesWorkspaceMap } from "@/features/sales-workspace/ui/sales-workspace-map";`
- **Live preview**: /design/components/sales-workspace-map/preview.html
- **Page**: /design/components/sales-workspace-map

## Guidelines

**Use it for** the sales workspace page's Map view.

**What you provide**:
- `graph: SalesWorkspaceGraph`, shaped `{ nodes, edges, updatedAt, notices }`.
  - Each node is `{ id, kind, label, description?, status?, href, stats? }`.
  - Each edge is `{ id, source, target, kind, label, status? }`, with `status` one of `active`, `paused`, `draft`, `configured`.
- `selectedId` (or `null`) and `onSelect(id)`.

**Layout**: a node's kind decides its lane:
- 0: lists and signals;
- 1: campaigns;
- 2: workflows and stage rules;
- 3: pipelines, stages and meetings.

Nodes sit at x = lane × 310, y = row × 165. The view fits the content, with zoom 0.15–1.5.

**Anatomy**:
- A node is `w-60 rounded-xl border bg-card p-4 shadow-sm`: a `text-[10px]` uppercase kind, the label in `text-sm font-semibold`, and the status in muted `text-xs` ("Configured" when absent).
- The selected node, and every node connected to it, gets `border-primary ring-2 ring-primary/15`.
- Edges are smoothstep with arrows: 2.5px `var(--primary)` when they touch the selection, otherwise 1px `var(--muted-foreground)`. Draft and paused edges are dashed `5 5`.
- The container is `h-[580px] rounded-xl border bg-muted/10`.

**Don't** use it to edit: nodes can't be dragged or connected. Changes are made on the source item.

**Known issue**: it doesn't pass `colorMode`, so in dark themes React Flow's zoom controls stay light and their icons are hard to see.

## API

```ts
export declare const KIND_LABELS: Record<SalesWorkspaceNodeKind, string>;
export declare function SalesWorkspaceMap({ graph, selectedId, onSelect }: {
    graph: SalesWorkspaceGraph;
    selectedId: string | null;
    onSelect: (id: string) => void;
}): JSX.Element;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  // SalesWorkspaceGraph (features/sales-workspace/schemas/sales-workspace.schema.ts).
  // Node ids follow the builder's "<kind>:<id>" shape; lanes come from the node kind.
  function node(kind, id, label, status, href, description) {
    return { id: kind + ":" + id, kind: kind, label: label, status: status, href: href, description: description };
  }
  function edge(id, source, target, kind, label, status) {
    return { id: id, source: source, target: target, kind: kind, label: label, status: status };
  }
  var GRAPH = {
    updatedAt: "2026-09-26T08:30:00.000Z",
    notices: [],
    nodes: [
      node("list", "l1", "DACH logistics CFOs", "ready", "/prospect-lists/l1", "Audience list"),
      node("signal", "s1", "Hiring SDRs monitor", "active", "/signals", "company · linkedin"),
      node("campaign", "c1", "Q4 DACH logistics — CFO outreach", "active", "/campaigns/c1", "Outreach sequence"),
      node("campaign", "c2", "Hiring-signal follow-up", "draft", "/campaigns/c2", "Outreach sequence"),
      node("stage_rule", "r1", "Create deal", "active", "/pipeline", "When entering Interested"),
      node("workflow", "w1", "Notify AE on positive reply", "active", "/workflows/w1"),
      node("people_stage", "ps1", "Replied", "active", "/pipeline"),
      node("people_stage", "ps2", "Interested", "active", "/pipeline"),
      node("deal_stage", "ds1", "Meeting booked", "open", "/deals")
    ],
    edges: [
      edge("m1", "list:l1", "campaign:c1", "membership", "Included audience", "configured"),
      edge("a1", "signal:s1", "campaign:c2", "automation", "Changed signal → launch if draft or stopped", "active"),
      edge("r1", "campaign:c1", "people_stage:ps1", "automation", "On replied", "active"),
      edge("p1", "people_stage:ps1", "people_stage:ps2", "automation", "Move on stage entry", "active"),
      edge("e1", "people_stage:ps2", "stage_rule:r1", "automation", "On entering stage", "active"),
      edge("d1", "stage_rule:r1", "deal_stage:ds1", "automation", "Create deal", "active")
    ]
  };
  function App() {
    var s = React.useState("campaign:c1"), selected = s[0], setSelected = s[1];
    return h(DC.SalesWorkspaceMap, { graph: GRAPH, selectedId: selected, onSelect: setSelected });
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Pipeline

- [DealCard](/design/components/deal-card.md): One draggable deal on the deals board, plus `DealCardPreview`, the tilted copy shown under the cursor while dragging.
- [DealColumn](/design/components/deal-column.md): One column of the deals board: a droppable, infinitely scrolling list of `DealCard`s under a header with the stage dot, a count badge and money totals.
- [MovableCardGrid](/design/components/movable-card-grid.md): A card grid the reader can rearrange.
- [StageColors](/design/components/stage-colors.md): The 17-colour palette for pipeline and deal stage accents, with helpers that return static Tailwind classes and a hex value for each colour.
