---
phase: 16-multi-signer-ui
plan: "02"
subsystem: ui
tags: [react, typescript, preparepanel, signer-list, send-block-validation]

# Dependency graph
requires:
  - phase: 16-multi-signer-ui
    plan: "01"
    provides: signers prop, onSignersChange, onUnassignedFieldIdsChange threaded from DocumentPageClient
provides:
  - SIGNER_COLORS palette constant ['#6366f1', '#f43f5e', '#10b981', '#f59e0b']
  - Signer list UI in PreparePanel (email input + "Add Signer" button + colored dot rows + aria-labeled × remove)
  - handleAddSigner / handleRemoveSigner with duplicate/format validation
  - Send-block validation: fetch fields → check no-signers guard → check unassigned isClientVisibleField fields
  - Inline error messages: "Add at least one signer..." and "{N} field(s) need a signer assigned..."
  - signers persisted to documents.signers via prepare POST body

affects: [16-04-dashboard-badge]

---

# Phase 16 Plan 02: PreparePanel Signer List UI Summary

## What Was Built

Modified `PreparePanel.tsx` (+104 lines) and `prepare/route.ts` (+5 lines):

**PreparePanel.tsx:**
- `SIGNER_COLORS = ['#6366f1', '#f43f5e', '#10b981', '#f59e0b']` — auto-assigned by index
- Props destructured: `signers`, `onSignersChange`, `onUnassignedFieldIdsChange`
- `handleAddSigner` — validates email format + duplicate, assigns next color from palette, calls `onSignersChange`
- `handleRemoveSigner` — filters signer from list, clears `unassignedFieldIds`
- Signer list UI section (Draft-only, inserted above Prepare and Send):
  - Email `<input>` + "Add Signer" `<button>` (height 32px)
  - Per-signer row: 8×8px colored dot (`w-2 h-2 rounded-full`) + email text + `×` remove button with `aria-label="Remove signer {email}"` (32×32px touch target)
  - Empty state: "No signers added yet."
  - Duplicate email warning: "That email is already in the signer list."
- `handlePrepare` extended: fetches current fields via `/api/documents/{id}/fields`, checks unassigned `isClientVisibleField` fields, sets `unassignedFieldIds` and shows inline error if found
- `signers` included in prepare POST body so `documents.signers` is persisted before send route reads it

**prepare/route.ts:**
- Body type extended with `signers?: DocumentSigner[]`
- DB update spreads `{ signers: body.signers }` when provided

# Tech tracking
tech-stack:
  added: []
  removed: []
  changed: []

# Metrics
duration: 4min
commit: 1c8551c
